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.