简体   繁体   中英

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

An integration test class is annotated with:

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

It's not supposed to run in a transaction so isn't marked as @Transactional but I'm getting errors when trying to perform persist, merge etc. operations on the EntityManager , which is injected using @PersistenceContext :

No transactional EntityManager available

How can this be resolved?

EDIT: As requested in the comments, the Spring version is 4.1.0.RELEASE and IntegrationTestConfig is below:

@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;
    }
}

If you are sure that you are never going to call entityManager.flush() , obtain the PersistenceContext as follows:

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

Why is this needed? Spring Data JPA hands out what is called a shared EntityManager when the @PersistenceContext annotation is used (without any attributes). Full details for this are available in the JavaDocs for org.springframework.orm.jpa.SharedEntityManagerCreator . This class maintains a lookup table where the EntityManager methods flush , merge , persist , refresh and remove are required to be run inside a transaction. So, any time it encounters a method call that is not inside a transaction, it bails out.

The annotation @PersistenceContext has a type attribute that can be set to one of PersistenceContextType.EXTENDED or PersistenceContextType.TRANSACTION , with the later being the default. Therefore, the default @PersistenceContext causes SharedEntityManagerCreator to look for a transaction and bail out if none is found.

Using PersistenceContextType.EXTENDED bypasses the need to check for a transaction when obtaining the EntityManager and therefore the code should work.


flush still cannot be called without a transaction because the JPA providers require it to be called only within a transactional context.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM