Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flush exception translation not working anymore with Hibernate 5.2 [SPR-14457] #19026

Closed
spring-projects-issues opened this issue Jul 12, 2016 · 1 comment
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) in: data Issues in data modules (jdbc, orm, oxm, tx) type: bug A general bug
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Jul 12, 2016

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.,

<tx:annotation-driven transaction-manager="transactionManager" order="10"/>

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:

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jul 13, 2016

Juergen Hoeller commented

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.

@spring-projects-issues spring-projects-issues added type: bug A general bug in: data Issues in data modules (jdbc, orm, oxm, tx) in: core Issues in core modules (aop, beans, core, context, expression) labels Jan 11, 2019
@spring-projects-issues spring-projects-issues added this to the 4.3.2 milestone Jan 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) in: data Issues in data modules (jdbc, orm, oxm, tx) type: bug A general bug
Projects
None yet
Development

No branches or pull requests

2 participants