如何在 Spring 中创建非事务性 JUnit 集成测试?

How to create non-transactional JUnit integration tests in Spring?

集成测试 class 注释为:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = IntegrationTestConfig.class)

它不应该在事务中 运行 所以 没有 标记为 @Transactional 但是我在尝试执行持久化时遇到错误, EntityManager 上的合并等操作,使用 @PersistenceContext:

注入

No transactional EntityManager available

如何解决?

编辑: 根据评论中的要求,Spring 版本为 4.1。0.RELEASE 和 IntegrationTestConfig 如下:

@EnableAspectJAutoProxy
@EnableAsync
@EnableScheduling
@EnableTransactionManagement
@Configuration
public class IntegrationTestConfig {
    /**
     * Override the existing JPA data source bean with a test data source.
     * @return test data source
     */
    @Bean
    public DataSource dataSource() {
        final SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
        dataSource.setDriverClass(org.h2.Driver.class);
        dataSource.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;INIT=CREATE SCHEMA IF NOT EXISTS mydb");
        dataSource.setUsername("sa");
        dataSource.setPassword("");
        return dataSource;
    }
}

如果您确定永远不会调用 entityManager.flush(),请按如下方式获取 PersistenceContext

@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;

为什么需要这个? Spring 数据JPA 手出来什么叫共享EntityManager@PersistenceContext annotation is used (without any attributes). Full details for this are available in the JavaDocs for org.springframework.orm.jpa.SharedEntityManagerCreator。此 class 维护查找 table,其中 EntityManager 方法 flushmergepersistrefreshremove 必须在交易中 运行。因此,只要遇到不在事务内的方法调用,它就会退出。

注释 @PersistenceContext 有一个 type 属性,可以设置为 PersistenceContextType.EXTENDEDPersistenceContextType.TRANSACTION 之一,后者为默认值。因此,默认 @PersistenceContext 会导致 SharedEntityManagerCreator 查找事务并在找到 none 时退出。

使用 PersistenceContextType.EXTENDED 绕过了在获取 EntityManager 时检查交易的需要,因此代码应该可以工作。


flush 仍然无法在没有事务的情况下调用,因为 JPA 提供程序要求它只能在事务上下文中调用。