1

我正在为 Spring Data JPA 存储库编写一个基于事务性 junit 的 IT 测试。要检查表中的行数,我使用侧 JDBCTemplate。

我注意到,在事务上下文中调用 oforg.springframework.data.repository.CrudRepository#save(S)不会生效。未执行 SQL 插入,表中的行数未增加。

但是,如果我在执行 SQL 插入并增加行数org.springframework.data.repository.CrudRepository#count之后调用。save(S)

我猜这是 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>
4

2 回答 2

4

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

保存新实例时,这意味着它只会在需要时执行插入以获取实体的 id。

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

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

  2. 显式调用您可能直接执行flush的操作或在使用 Spring Data JPA 时通过EntityManagersaveAndFlush

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

第三个是你看到的效果。

请注意,细节有点复杂,因为您可以配置很多这样的东西。像往常一样,Vlad Mihalcea 写了一篇关于它的优秀文章

于 2018-10-09T08:01:32.043 回答
0

为了使测试数据不污染数据库,在使用Spring-test的单元测试时,默认会回滚事务,即@Rollback默认为true。如果要在不回滚的情况下测试数据,可以设置 @Rollback(value = false) 。如果你使用的是 MySQL 数据库,设置自动回滚后,如果发现事务仍然没有回滚,可以检查数据库引擎是否为 Innodb ,因为其他数据库引擎如 MyISAM 和 Memory 不支持事务。

于 2018-10-09T07:02:45.163 回答