You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I am porting from Spring 3.2+Hibernate 4.1 to Spring 4.3+Hibernate 5.2. There appears to be an issue with Aspect ordering between aspects detected using annotations and those added manually with Advised.addAdvisor(). More specifically, advisors added with Advised.addAdvisor() are added after those discovered using annotations unless 'beforeExistingAdvisors' is added, in which case it is before all others.
The problem arises when using annotation-based transactions, i.e.,
in combination with org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor.
The PersistenceExceptionTranslationPostProcessor adds the Aspect using Advised.addAdvisor() after the BeanFactoryTransactionAttributeSourceAdvisor. The result is that when the a transaction completes and flushes cached operations to the database, exceptions that arise are not processed by the PersistenceExceptionTranslator since it has already completed. The result is that Hibernate exceptions are not translated into Spring exceptions for database operations that occur during commit.
This was working correctly in the previous versions (Spring 3.2+Hibernate 4.1). I have tried adding 'order' to the PersistenceExceptionTranslationPostProcessor, but it is has no effect.
Below are two stack traces illustrating the issue.
The first shows that the PersistenceExceptionTranslator is invoked within the TransactionInterceptor:
PersistenceExceptionTranslationInterceptor.invoke(MethodInvocation) line: 136 ReflectiveMethodInvocation.proceed() line: 179 TransactionInterceptor$1.proceedWithInvocation() line: 99 TransactionInterceptor(TransactionAspectSupport).invokeWithinTransaction(Method, Class, InvocationCallback) line: 281
TransactionInterceptor.invoke(MethodInvocation) line: 96
ReflectiveMethodInvocation.proceed() line: 179
AspectJAfterThrowingAdvice.invoke(MethodInvocation) line: 62
ReflectiveMethodInvocation.proceed() line: 168
ExposeInvocationInterceptor.invoke(MethodInvocation) line: 92 ReflectiveMethodInvocation.proceed() line: 179
JdkDynamicAopProxy.invoke(Object, Method, Object[]) line: 213 $Proxy48.storeAnalysisRule(String, AnalysisRule) line: not available
AnalysisRuleTest.duplicateSaveError() line: 71
The second shows that the exception is occurring during the flush() operation, after the PersistenceExceptionTranslator has completed:
Stacktrace was: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute batch at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:147) at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155) at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:162) at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1403) at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:473) at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3133) at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2370) at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:467) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:146) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:220) at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:68) at org.springframework.orm.hibernate5.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:581) at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761) at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730) at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:485) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) at com.sun.proxy.$Proxy48.storeAnalysisRule(Unknown Source) at test.com.leeriver.trading.account.AnalysisRuleTest.duplicateSaveError(AnalysisRuleTest.java:71) Caused by: org.hibernate.exception.ConstraintViolationException: could not execute batch at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:112) at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111) at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.performExecution(BatchingBatch.java:119) at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.doExecuteBatch(BatchingBatch.java:97) at org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl.execute(AbstractBatchImpl.java:147) at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.executeBatch(JdbcCoordinatorImpl.java:206) at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:611) at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:456) at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337) at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1397) ... 53 more Caused by: java.sql.BatchUpdateException: integrity constraint violation: unique constraint or index violation; USER_RULE_IDX table: USERANALYSISRULE at org.hsqldb.jdbc.JDBCPreparedStatement.executeBatch(Unknown Source) at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297) at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297) at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297) at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.performExecution(BatchingBatch.java:110) ... 61 more
As with #19024, the root of the problem here seems to be Hibernate 5.2 throwing plain JPA PersistenceExceptions instead of HibernateExceptions in a few cases now, in particular for a flush, which our HibernateTransactionManager's built-in exception translation is not prepared for. This is a wider-ranging problem than just extending HibernateExceptionTranslator towards JPA exceptions, also affecting HibernateTemplate usage etc. We need to update our built-in Hibernate exception translation steps as well.
In a typical PersistenceExceptionTranslationPostProcessor setup, commit/flush exceptions are not actually handled by the post-processor. You may enforce this through configuring beforeExistingAdvisors=true, but typically this is handled for you in the transaction manager implementation already. So I'll repurpose this ticket towards the fix suggested above.
Will Darby opened SPR-14457 and commented
I am porting from Spring 3.2+Hibernate 4.1 to Spring 4.3+Hibernate 5.2. There appears to be an issue with Aspect ordering between aspects detected using annotations and those added manually with Advised.addAdvisor(). More specifically, advisors added with Advised.addAdvisor() are added after those discovered using annotations unless 'beforeExistingAdvisors' is added, in which case it is before all others.
The problem arises when using annotation-based transactions, i.e.,
in combination with org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor.
The PersistenceExceptionTranslationPostProcessor adds the Aspect using Advised.addAdvisor() after the BeanFactoryTransactionAttributeSourceAdvisor. The result is that when the a transaction completes and flushes cached operations to the database, exceptions that arise are not processed by the PersistenceExceptionTranslator since it has already completed. The result is that Hibernate exceptions are not translated into Spring exceptions for database operations that occur during commit.
This was working correctly in the previous versions (Spring 3.2+Hibernate 4.1). I have tried adding 'order' to the PersistenceExceptionTranslationPostProcessor, but it is has no effect.
Below are two stack traces illustrating the issue.
The first shows that the PersistenceExceptionTranslator is invoked within the TransactionInterceptor:
PersistenceExceptionTranslationInterceptor.invoke(MethodInvocation) line: 136 ReflectiveMethodInvocation.proceed() line: 179 TransactionInterceptor$1.proceedWithInvocation() line: 99 TransactionInterceptor(TransactionAspectSupport).invokeWithinTransaction(Method, Class, InvocationCallback) line: 281
TransactionInterceptor.invoke(MethodInvocation) line: 96
ReflectiveMethodInvocation.proceed() line: 179
AspectJAfterThrowingAdvice.invoke(MethodInvocation) line: 62
ReflectiveMethodInvocation.proceed() line: 168
ExposeInvocationInterceptor.invoke(MethodInvocation) line: 92 ReflectiveMethodInvocation.proceed() line: 179
JdkDynamicAopProxy.invoke(Object, Method, Object[]) line: 213 $Proxy48.storeAnalysisRule(String, AnalysisRule) line: not available
AnalysisRuleTest.duplicateSaveError() line: 71
The second shows that the exception is occurring during the flush() operation, after the PersistenceExceptionTranslator has completed:
Stacktrace was: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute batch at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:147) at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155) at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:162) at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1403) at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:473) at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3133) at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2370) at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:467) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:146) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:220) at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:68) at org.springframework.orm.hibernate5.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:581) at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761) at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730) at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:485) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) at com.sun.proxy.$Proxy48.storeAnalysisRule(Unknown Source) at test.com.leeriver.trading.account.AnalysisRuleTest.duplicateSaveError(AnalysisRuleTest.java:71) Caused by: org.hibernate.exception.ConstraintViolationException: could not execute batch at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:112) at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111) at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.performExecution(BatchingBatch.java:119) at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.doExecuteBatch(BatchingBatch.java:97) at org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl.execute(AbstractBatchImpl.java:147) at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.executeBatch(JdbcCoordinatorImpl.java:206) at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:611) at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:456) at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337) at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1397) ... 53 more Caused by: java.sql.BatchUpdateException: integrity constraint violation: unique constraint or index violation; USER_RULE_IDX table: USERANALYSISRULE at org.hsqldb.jdbc.JDBCPreparedStatement.executeBatch(Unknown Source) at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297) at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297) at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297) at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.performExecution(BatchingBatch.java:110) ... 61 more
Affects: 4.3.1
Issue Links:
The text was updated successfully, but these errors were encountered: