Steve Chambers Steve Chambers - 8 months ago 46
Java Question

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

An integration test class is annotated with:

@ContextConfiguration(classes = IntegrationTestConfig.class)

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

No transactional EntityManager available

How can this be resolved?

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

public class IntegrationTestConfig {
* Override the existing JPA data source bean with a test data source.
* @return test data source
public DataSource dataSource() {
final SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
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.