Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Untranslated UnexpectedRollbackException caused by JPA Integrity violation Exception due to deferred operations in MS SQL [SPR-3849] #8529
I just checked with latest available spring (2.0.6), hibernate (3.2.5), hibernate entity manager and MS SQL database (both MSDE and MS SQL Server 2000), jtds driver.
As I see it is still not solved, that is, with declarative transactions and exception translation, having business manager class annotated with
I get UnexpectedRollbackException caused by integrity violation exception, because actual database operation and constraints verification are seems deferred to commit() in MS SQL (much like in Oracle I think).
Here's exception stack trace:
org.springframework.transaction.UnexpectedRollbackException: JPA transaction unexpectedly rolled back (maybe marked rollback-only after a failed operation); nested exception is javax.persistence.RollbackException: Error while commiting the transaction
... removed application code calls ...
Caused by: org.hibernate.exception.ConstraintViolationException: could not update: [com.vyke.mobile.server.domain.Client#4]
I found very similar problem description here :
it is dated by last year..
I was able to solve the problem only by verification during business method invocation if conflicting record already exists in database using extra select statement.
IMO it is very rough solution and quite bad problem in Spring, as the situation is quite common and it voids all efforts made to improve persistence exception
Affects: 2.0.5, 2.0.6, 2.1 M3
Juergen Hoeller commented
This is not so much a bug of Spring rather than a limitation in JPA's exception hierarchy. JPA simply throws a plain RollbackException in such a case, which suggests an unexpected rollback... That RollbackException is masking an underlying constraint violation, but that's unfortunately not reflected in the exception type at all. Native Hibernate has a finer-grained exception hierarchy there, clearly indicating a constraint violation, which allows Spring to cleanly detect and convert such an exception.
We can do some analysis of the underlying native exception even in the case of JPA... The mechanism is in place already: Our JpaDialect SPI has a persistence exception translator facility. I consider this JIRA issue as an enhancement request for introspecting the native Hibernate exception in our HibernateJpaDialect, also introspecting the underlying root cause of a JPA RollbackException (as handled in JpaTransactionManager). Scheduled for Spring 2.1.
Dmitry V. Zemnitskiy commented
Maybe I miss something related to nested transactions (why ever the UnexpectedRollbackException was added), but it should be relatively easy to solve this situation, as u explained above:
Though, maybe it would be good to look first at closed issues and investigate why ever this exception was added? My first impression after briefly scanning forum is its addition was related to nested transactions.
Juergen Hoeller commented
After some research, there is actually a bug hiding here - in the form of a misunderstanding of exception semantics: The JPA RollbackException will be thrown for any kind of commit failure, not just for unexpected rollback decisions (i.e. it is not equivalent to the JTA RollbackException). RollbackException is effectively just a holder for a specific exception; this is the case for Hibernate as well as for OpenJPA.
Hence I've revised JpaTransactionManager to convert JPA RollbackExceptions into Spring TransactionSystemExceptions, providing fine-grained commit exceptions through translating JPA RollbackException root causes before that default TransactionSystemException conversion. This means that a JpaDialect implementation will see the root cause of a RollbackException through a "translateExceptionIfPossible" call: By default, a more specific JPA PersistenceException (if any) will get introspected and translated there. This will make it into both 2.1 M4 and 2.0.7; the change will be available in tonight's nightly snapshots already.
However, Hibernate EntityManager unfortunately does not wrap specific JPA PersistenceExceptions with a RollbackException; it rather wraps its native HibernateExceptions with such a RollbackException. This means that the above-mentioned standard translation of JPA root causes won't kick in there. Furthermore, Hibernate EntityManager wraps constraint violations with EntityExistsExceptions, not clearly indicating a constraint violation (this even marked with FIXME in Hibernate EntityManager 3.3.1). So in order to still translate the actual root cause there, I've added native Hibernate exception conversion to HibernateJpaDialect, for any kind of PersistenceException with a HibernateException root cause. This is pretty powerful but may introduce subtle issues with backwards compatibility, hence I've only implemented that change for 2.1 M4. If you want equivalent behavior in 2.0.7, then extend HibernateJpaDialect and override "translateExceptionIfPossible" accordingly.