我正在为Spring Data JPA存储库编写一个基于事务的基于junit的IT测试。 要检查表中的行数,我使用了侧面JDBCTemplate。
我注意到,在事务上下文中,调用org.springframework.data.repository.CrudRepository#save(S)
不会生效。未执行SQL插入,表中的行数未增加。
但是如果我在org.springframework.data.repository.CrudRepository#count
之后调用save(S)
,则会执行SQL插入操作,并且行数会增加。
我想这是JPA缓存的行为,但是它如何详细工作?
使用Spring Boot的代码:
@RunWith(SpringRunner.class)
@SpringBootTest
public class ErrorMessageEntityRepositoryTest {
@Autowired
private ErrorMessageEntityRepository errorMessageEntityRepository;
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
@Transactional
public void save() {
ErrorMessageEntity errorMessageEntity = aDefaultErrorMessageEntity().withUuid(null).build();
assertTrue(TestTransaction.isActive());
int sizeBefore= JdbcTestUtils.countRowsInTable(jdbcTemplate, "error_message");
ErrorMessageEntity saved = errorMessageEntityRepository.save(errorMessageEntity);
errorMessageEntityRepository.count(); // [!!!!] if comment this line test will fail
int sizeAfter= JdbcTestUtils.countRowsInTable(jdbcTemplate, "error_message");
Assert.assertEquals(sizeBefore+1, sizeAfter);
}
实体:
@Entity(name = "error_message")
public class ErrorMessageEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private UUID uuid;
@NotNull
private String details;
存储库:
public interface ErrorMessageEntityRepository extends CrudRepository<ErrorMessageEntity, UUID>
答案 0 :(得分:1)
您是正确的,这是JPA运作方式的结果。 JPA尝试尽可能长时间地延迟SQL语句的执行。
保存新实例时,这意味着仅在需要获取实体ID时才执行插入操作。
仅当发生刷新事件时,存储在持久性上下文中的所有更改才会刷新到数据库。该事件的发生有三个触发因素:
持久性上下文的关闭将刷新所有更改。在典型的设置中,这对于事务提交很严格。
在flush
上显式调用EntityManager
,您可以直接执行此操作,也可以在通过saveAndFlush
使用Spring Data JPA时进行调用
在执行查询之前。由于您通常希望查看查询中的更改。
数字3是您所看到的效果。
请注意,由于您可以配置很多此类内容,因此细节稍微复杂一些。 As usual, Vlad Mihalcea has written an excellent post about it。
答案 1 :(得分:0)
为了使测试数据不会污染数据库,在使用Spring-test的单元测试时,默认情况下将回滚事务,即@Rollback默认为true。如果要在不回滚的情况下测试数据,则可以设置@Rollback(value = false)。如果使用MySQL数据库,则在设置自动回滚后,如果发现事务仍未回滚,则可以检查数据库引擎是否为Innodb,因为其他数据库引擎(如MyISAM和Memory)不支持事务。