在Spring Data JPA存储库上调用count()方法时,JPA缓存行为

时间:2018-10-09 06:34:26

标签: spring-data-jpa spring-transactions hibernate-cache

我正在为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>

2 个答案:

答案 0 :(得分:1)

您是正确的,这是JPA运作方式的结果。 JPA尝试尽可能长时间地延迟SQL语句的执行。

保存新实例时,这意味着仅在需要获取实体ID时才执行插入操作。

仅当发生刷新事件时,存储在持久性上下文中的所有更改才会刷新到数据库。该事件的发生有三个触发因素:

  1. 持久性上下文的关闭将刷新所有更改。在典型的设置中,这对于事务提交很严格。

  2. flush上显式调用EntityManager,您可以直接执行此操作,也可以在通过saveAndFlush使用Spring Data JPA时进行调用

  3. 在执行查询之前。由于您通常希望查看查询中的更改。

数字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)不支持事务。