Spring 引导:H2 实际上并未从数据库中检索

Spring Boot: H2 Not Actually Retrieving From Database

我正在尝试在 Spring Boot 中编写一个简单的存储库测试。测试代码如下所示:

public class UserRepositoryTest {
    private final TestEntityManager entityManager;
    private final UserRepository userRepository;

    @Autowired
    public UserRepositoryTest(TestEntityManager entityManager, UserRepository userRepository) {
        this.entityManager = entityManager;
        this.userRepository = userRepository;
    }

    @Test
    public void test() {
        String firstName = "Frank";
        String lastName = "Sample";
        String email = "frank@example.com";
        String username = "frank@example.com";
        String password = "floople";
        String passwordConfirm = "floople";

        RegisterUserRequest registerUserRequest = new RegisterUserRequest(firstName, lastName, email, username, password, passwordConfirm);
        User user = new User(registerUserRequest);
        user.setSpinsRemaining(0);
        userRepository.save(user);
        userRepository.setSpinsRemainingToTen();
        User found = userRepository.findByUsername(username);
        assertThat(found.getSpinsRemaining()).isEqualTo(10);
    }

我期望发生的是新的用户对象被持久化到数据库中,数据库中的行被修改以将 spinsRemaining 设置为 10,然后现在修改的行从 H2 中检索并被推入一个名为 "found" 的新变量。 "found" 变量将指向一个 User 对象的实例,其中还有十次旋转。

实际发生的是 "found" 变量指向与 "user" 变量完全相同的 User 实例。事实上,如果我在将 "user" 变量持久化到 H2 之后修改了一些 属性,则生成的 "found" 对象也具有修改后的 属性。根据 IntelliJ,"user" 和 "found" 都指向同一事物。这怎么可能?

Hibernate 在内存中缓存事务内的实体 ("first level cache")。 - 每次它从数据库中检索一个实体时(或者当它被实体 ID 要求这样做时)它会首先在缓存中查找它,所以你不会有一个实体的多个实例具有相同的 ID。

但在测试中 sometimes useful 有一个 "fresh" 实体,因为它可以发现您的持久性中的错误 configuration/code。你需要做什么:

  • 调用 EntityManager#flush - 这将强制将您的更改同步到数据库(save 方法不能保证在事务内部调用时)。
  • 调用 EntityManager#clear - Hibernate 将忘记以前的实体实例并将再次开始从数据库中获取。

或者:您也可以将 Spring 存储库方法指示为 clear entities automatically after a modifying query。 - 但这会清除所有实体实例,而不仅仅是您正在修改的实体实例,因此在您的应用程序代码中可能不需要它。