-
Notifications
You must be signed in to change notification settings - Fork 41.9k
Description
HibernateJpaAutoConfiguration should be applied before DatasourceTransactionManagerAutoconfiguration
Explanation:
HibernateJpaAutoConfiguration imports HibernateJpaBaseConfiguration which contains a Bean definition of a JPATransactionManager with ConditionalOnMissingBean(TransactionManager) (in superclass JpaBaseConfiguration):
@Bean
@ConditionalOnMissingBean(TransactionManager.class)
public PlatformTransactionManager transactionManager(
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
return transactionManager;
}The DatasourceTransactionManagerAutoConfiguration does also define a TransactionManager Bean with the same condition:
@Bean
@ConditionalOnMissingBean(TransactionManager.class)
DataSourceTransactionManager transactionManager(Environment environment, DataSource dataSource,
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
DataSourceTransactionManager transactionManager = createTransactionManager(environment, dataSource);
transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
return transactionManager;
}If the application uses Hibernate, the Hibernate auto-configuration should match, which means that the HibernateJpaAutoConfiguration should be applied before DatasourceTransactionManagerAutoConfiguration.
Currently, there is no explicit before/after Condition for these Autoconfigurations, but the 'natural' sort order leads 'by chance' to the right order.
We provided for our application a additional auto-configuration with these conditions:
@AutoConfiguration(
after = {RestTemplateAutoconfiguration.class, TransactionAutoConfiguration.class}
)which leaded to a different order of many Spring auto-configuration, especially now sorting DatasourceTransactionManagerAutoConfiguration before HibernateJpaAutoConfiguration. As a result, we saw this exception during execution of the application:
14:22:47 [43-exec-7] ERROR d.l.a.a.b.r.GlobalExceptionHandler - Caught unhandled exception
org.springframework.dao.InvalidDataAccessApiUsageException: no transaction is in progress
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:400)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:234)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:550)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:243)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:152)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:164)
...
Caused by: jakarta.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.internal.AbstractSharedSessionContract.checkTransactionNeededForUpdateOperation(AbstractSharedSessionContract.java:483)
at org.hibernate.internal.SessionImpl.checkTransactionNeededForUpdateOperation(SessionImpl.java:2528)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1406)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1401)