Browse Source

Translate Hibernate TransactionException through SQLException cause

Closes gh-31274
pull/31416/head
Juergen Hoeller 1 year ago
parent
commit
e76b453685
  1. 4
      spring-orm/src/main/java/org/springframework/orm/jpa/JpaTransactionManager.java
  2. 31
      spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java
  3. 2
      spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java

4
spring-orm/src/main/java/org/springframework/orm/jpa/JpaTransactionManager.java

@ -589,6 +589,10 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager @@ -589,6 +589,10 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager
}
}
catch (PersistenceException ex) {
DataAccessException dae = getJpaDialect().translateExceptionIfPossible(ex);
if (dae != null) {
throw dae;
}
throw new TransactionSystemException("Could not roll back JPA transaction", ex);
}
finally {

31
spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java vendored

@ -59,6 +59,7 @@ import org.springframework.dao.InvalidDataAccessResourceUsageException; @@ -59,6 +59,7 @@ import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.PessimisticLockingFailureException;
import org.springframework.jdbc.datasource.ConnectionHandle;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.support.SQLExceptionSubclassTranslator;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.lang.Nullable;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
@ -74,7 +75,7 @@ import org.springframework.util.ReflectionUtils; @@ -74,7 +75,7 @@ import org.springframework.util.ReflectionUtils;
/**
* {@link org.springframework.orm.jpa.JpaDialect} implementation for Hibernate.
* Compatible with Hibernate ORM 5.5/5.6 as well as 6.0/6.1/6.2.
* Compatible with Hibernate ORM 5.5/5.6 as well as 6.0/6.1/6.2/6.3.
*
* @author Juergen Hoeller
* @author Costin Leau
@ -91,6 +92,9 @@ public class HibernateJpaDialect extends DefaultJpaDialect { @@ -91,6 +92,9 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
@Nullable
private SQLExceptionTranslator jdbcExceptionTranslator;
@Nullable
private SQLExceptionTranslator transactionExceptionTranslator = new SQLExceptionSubclassTranslator();
/**
* Set whether to prepare the underlying JDBC Connection of a transactional
@ -121,14 +125,22 @@ public class HibernateJpaDialect extends DefaultJpaDialect { @@ -121,14 +125,22 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
* <p>Applied to any detected {@link java.sql.SQLException} root cause of a Hibernate
* {@link JDBCException}, overriding Hibernate's own {@code SQLException} translation
* (which is based on a Hibernate Dialect for a specific target database).
* <p>As of 6.1, also applied to {@link org.hibernate.TransactionException} translation
* with a {@link SQLException} root cause (where Hibernate does not translate itself
* at all), overriding Spring's default {@link SQLExceptionSubclassTranslator} there.
* @param exceptionTranslator the {@link SQLExceptionTranslator} to delegate to, or
* {@code null} for none. By default, a {@link SQLExceptionSubclassTranslator} will
* be used for {@link org.hibernate.TransactionException} translation as of 6.1;
* this can be reverted to pre-6.1 behavior through setting {@code null} here.
* @since 5.1
* @see java.sql.SQLException
* @see org.hibernate.JDBCException
* @see org.springframework.jdbc.support.SQLExceptionSubclassTranslator
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
*/
public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
this.jdbcExceptionTranslator = jdbcExceptionTranslator;
public void setJdbcExceptionTranslator(@Nullable SQLExceptionTranslator exceptionTranslator) {
this.jdbcExceptionTranslator = exceptionTranslator;
this.transactionExceptionTranslator = exceptionTranslator;
}
@ -245,7 +257,16 @@ public class HibernateJpaDialect extends DefaultJpaDialect { @@ -245,7 +257,16 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
DataAccessException dae = this.jdbcExceptionTranslator.translate(
"Hibernate operation: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException());
if (dae != null) {
throw dae;
return dae;
}
}
if (this.transactionExceptionTranslator != null && ex instanceof org.hibernate.TransactionException) {
if (ex.getCause() instanceof SQLException sqlEx) {
DataAccessException dae = this.transactionExceptionTranslator.translate(
"Hibernate transaction: " + ex.getMessage(), null, sqlEx);
if (dae != null) {
return dae;
}
}
}

2
spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java vendored

@ -45,7 +45,7 @@ import org.springframework.util.ClassUtils; @@ -45,7 +45,7 @@ import org.springframework.util.ClassUtils;
/**
* {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Hibernate.
* Compatible with Hibernate ORM 5.5/5.6 as well as 6.0/6.1/6.2.
* Compatible with Hibernate ORM 5.5/5.6 as well as 6.0/6.1/6.2/6.3.
*
* <p>Exposes Hibernate's persistence provider and Hibernate's Session as extended
* EntityManager interface, and adapts {@link AbstractJpaVendorAdapter}'s common

Loading…
Cancel
Save