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。 - 但这会清除所有实体实例,而不仅仅是您正在修改的实体实例,因此在您的应用程序代码中可能不需要它。
我正在尝试在 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。 - 但这会清除所有实体实例,而不仅仅是您正在修改的实体实例,因此在您的应用程序代码中可能不需要它。