diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java index 085bb568a36c..a400ed99c2bf 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java @@ -4,7 +4,6 @@ */ package org.hibernate.community.dialect; -import java.lang.invoke.MethodHandles; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; @@ -47,7 +46,6 @@ import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor; import org.hibernate.exception.spi.ViolatedConstraintNameExtractor; -import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.internal.util.StringHelper; import org.hibernate.query.SemanticException; @@ -76,7 +74,6 @@ import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry; import org.hibernate.type.spi.TypeConfiguration; -import org.jboss.logging.Logger; import jakarta.persistence.GenerationType; import jakarta.persistence.TemporalType; @@ -124,7 +121,6 @@ */ public class CockroachLegacyDialect extends Dialect { - private static final CoreMessageLogger LOG = Logger.getMessageLogger( MethodHandles.lookup(), CoreMessageLogger.class, CockroachLegacyDialect.class.getName() ); // KNOWN LIMITATIONS: // * no support for java.sql.Clob @@ -188,11 +184,6 @@ protected static DatabaseVersion parseVersion(String versionString ) { } if ( databaseVersion == null ) { // Recur to the default version of the no-args constructor - LOG.unableToDetermineCockroachDatabaseVersion( - DEFAULT_VERSION.getDatabaseMajorVersion() + "." + - DEFAULT_VERSION.getDatabaseMinorVersion() + "." + - DEFAULT_VERSION.getDatabaseMicroVersion() - ); databaseVersion = DEFAULT_VERSION; } return databaseVersion; diff --git a/hibernate-core/src/main/java/org/hibernate/NonUniqueResultException.java b/hibernate-core/src/main/java/org/hibernate/NonUniqueResultException.java index 879594b863ab..f021e3589560 100644 --- a/hibernate-core/src/main/java/org/hibernate/NonUniqueResultException.java +++ b/hibernate-core/src/main/java/org/hibernate/NonUniqueResultException.java @@ -16,6 +16,7 @@ * * @see jakarta.persistence.Query#getSingleResult * @see org.hibernate.query.SelectionQuery#getSingleResult + * @see jakarta.persistence.NonUniqueResultException */ public class NonUniqueResultException extends HibernateException { diff --git a/hibernate-core/src/main/java/org/hibernate/PessimisticLockException.java b/hibernate-core/src/main/java/org/hibernate/PessimisticLockException.java index e40834e8d754..d6ab0542a6ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/PessimisticLockException.java +++ b/hibernate-core/src/main/java/org/hibernate/PessimisticLockException.java @@ -9,7 +9,13 @@ /** * Thrown when a pessimistic locking conflict occurs. * + * @apiNote When a conflict is detected while acquiring a database-level lock, + * {@link org.hibernate.exception.LockAcquisitionException} is preferred. + * * @author Scott Marlow + * + * @see jakarta.persistence.PessimisticLockException + * @see org.hibernate.exception.LockAcquisitionException */ public class PessimisticLockException extends JDBCException { /** @@ -22,4 +28,14 @@ public class PessimisticLockException extends JDBCException { public PessimisticLockException(String message, SQLException sqlException, String sql) { super( message, sqlException, sql ); } + /** + * Constructs a {@code PessimisticLockException} using the specified information. + * + * @param message A message explaining the exception condition + * @param sqlException The underlying SQL exception + */ + public PessimisticLockException(String message, SQLException sqlException) { + super( message, sqlException ); + + } } diff --git a/hibernate-core/src/main/java/org/hibernate/QueryTimeoutException.java b/hibernate-core/src/main/java/org/hibernate/QueryTimeoutException.java index 8c5503cb1c1c..431badc12eca 100644 --- a/hibernate-core/src/main/java/org/hibernate/QueryTimeoutException.java +++ b/hibernate-core/src/main/java/org/hibernate/QueryTimeoutException.java @@ -14,6 +14,7 @@ * * @see jakarta.persistence.Query#setTimeout * @see org.hibernate.query.CommonQueryContract#setTimeout + * @see jakarta.persistence.QueryTimeoutException */ public class QueryTimeoutException extends JDBCException { /** diff --git a/hibernate-core/src/main/java/org/hibernate/StaleStateException.java b/hibernate-core/src/main/java/org/hibernate/StaleStateException.java index 039eeaf1d6e9..b9079ce6b10b 100644 --- a/hibernate-core/src/main/java/org/hibernate/StaleStateException.java +++ b/hibernate-core/src/main/java/org/hibernate/StaleStateException.java @@ -11,6 +11,8 @@ * does not exist. * * @author Gavin King + * + * @see jakarta.persistence.OptimisticLockException */ public class StaleStateException extends HibernateException { /** diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java index 756421510ce2..a488880c3f35 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java @@ -4,7 +4,6 @@ */ package org.hibernate.dialect; -import java.lang.invoke.MethodHandles; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; @@ -48,7 +47,6 @@ import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor; import org.hibernate.exception.spi.ViolatedConstraintNameExtractor; -import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.query.SemanticException; @@ -77,8 +75,6 @@ import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry; import org.hibernate.type.spi.TypeConfiguration; -import org.jboss.logging.Logger; - import jakarta.persistence.GenerationType; import jakarta.persistence.TemporalType; @@ -128,7 +124,6 @@ */ public class CockroachDialect extends Dialect { - private static final CoreMessageLogger LOG = Logger.getMessageLogger( MethodHandles.lookup(), CoreMessageLogger.class, CockroachDialect.class.getName() ); // KNOWN LIMITATIONS: // * no support for java.sql.Clob @@ -204,11 +199,6 @@ public static DatabaseVersion parseVersion( String versionString ) { databaseVersion= new SimpleDatabaseVersion( majorVersion, minorVersion, microVersion); } if ( databaseVersion == null ) { - LOG.unableToDetermineCockroachDatabaseVersion( - MINIMUM_VERSION.getDatabaseMajorVersion() + "." + - MINIMUM_VERSION.getDatabaseMinorVersion() + "." + - MINIMUM_VERSION.getDatabaseMicroVersion() - ); databaseVersion = MINIMUM_VERSION; } return databaseVersion; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java index c4b01cae89ff..abb5aeef3779 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java @@ -15,7 +15,6 @@ import java.util.TimeZone; import org.checkerframework.checker.nullness.qual.Nullable; -import org.hibernate.PessimisticLockException; import org.hibernate.QueryTimeoutException; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.boot.model.TypeContributions; @@ -38,6 +37,7 @@ import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.ConstraintViolationException.ConstraintKind; import org.hibernate.exception.LockAcquisitionException; +import org.hibernate.exception.LockTimeoutException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor; import org.hibernate.exception.spi.ViolatedConstraintNameExtractor; @@ -810,7 +810,7 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() { new LockAcquisitionException(message, sqlException, sql); case 50200 -> // LOCK NOT AVAILABLE - new PessimisticLockException(message, sqlException, sql); + new LockTimeoutException(message, sqlException, sql); case 23505 -> // Unique index or primary key violation new ConstraintViolationException( message, sqlException, sql, ConstraintKind.UNIQUE, @@ -828,6 +828,7 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() { new ConstraintViolationException( message, sqlException, sql, ConstraintKind.CHECK, getViolatedConstraintNameExtractor().extractConstraintName( sqlException ) ); case 57014 -> + // QUERY CANCELLED new QueryTimeoutException( message, sqlException, sql ); default -> null; }; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java index de05cd40a7b5..5a610af7b5f4 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java @@ -9,7 +9,7 @@ import java.sql.Types; import java.util.Set; -import org.hibernate.PessimisticLockException; +import org.hibernate.QueryTimeoutException; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.boot.model.TypeContributions; import org.hibernate.dialect.aggregate.AggregateSupport; @@ -27,6 +27,7 @@ import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.ConstraintViolationException.ConstraintKind; import org.hibernate.exception.LockAcquisitionException; +import org.hibernate.exception.SnapshotIsolationException; import org.hibernate.exception.LockTimeoutException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor; @@ -348,21 +349,24 @@ public ViolatedConstraintNameExtractor getViolatedConstraintNameExtractor() { case 1048 -> extractUsingTemplate( "Column '", "'", sqle.getMessage() ); default -> null; } ); + @Override public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() { return (sqlException, message, sql) -> { switch ( sqlException.getErrorCode() ) { - // If @@innodb_snapshot_isolation is set (default since 11.6.2), - // if an attempt to acquire a lock on a record that does not exist in the current read view is made, - // an error DB_RECORD_CHANGED will be raised. + case 1205: // ER_LOCK_WAIT_TIMEOUT + return new LockTimeoutException( message, sqlException, sql ); case 1020: + // If @@innodb_snapshot_isolation is set (default since 11.6.2), + // and an attempt to acquire a lock on a record that does not exist + // in the current read view is made, error DB_RECORD_CHANGED is raised + return new SnapshotIsolationException( message, sqlException, sql ); + case 3572: // ER_LOCK_NOWAIT + case 1207: // ER_READ_ONLY_TRANSACTION + case 1206: // ER_LOCK_TABLE_FULL return new LockAcquisitionException( message, sqlException, sql ); - case 1205: - case 3572: - return new PessimisticLockException( message, sqlException, sql ); - case 1207: - case 1206: - return new LockAcquisitionException( message, sqlException, sql ); + case 3024: // ER_QUERY_TIMEOUT + return new QueryTimeoutException( message, sqlException, sql ); case 1062: // Unique constraint violation return new ConstraintViolationException( message, sqlException, sql, ConstraintKind.UNIQUE, diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java index 850b4770b337..05c22046599e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java @@ -17,7 +17,7 @@ import org.hibernate.Length; import org.hibernate.LockOptions; -import org.hibernate.PessimisticLockException; +import org.hibernate.QueryTimeoutException; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.boot.model.TypeContributions; import org.hibernate.cfg.AvailableSettings; @@ -1243,12 +1243,15 @@ public boolean supportsLockTimeouts() { public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() { return (sqlException, message, sql) -> { switch ( sqlException.getErrorCode() ) { - case 1205: - case 3572: - return new PessimisticLockException( message, sqlException, sql ); - case 1207: - case 1206: + case 1205: // ER_LOCK_WAIT_TIMEOUT + return new LockTimeoutException( message, sqlException, sql ); + case 3572: // ER_LOCK_NOWAIT + case 1207: // ER_READ_ONLY_TRANSACTION + case 1206: // ER_LOCK_TABLE_FULL return new LockAcquisitionException( message, sqlException, sql ); + case 3024: // ER_QUERY_TIMEOUT + case 1317: // ER_QUERY_INTERRUPTED + return new QueryTimeoutException( message, sqlException, sql ); case 1062: // Unique constraint violation return new ConstraintViolationException( message, sqlException, sql, ConstraintKind.UNIQUE, diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java index 7badbd690b9f..37c2c201dcb3 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java @@ -21,7 +21,6 @@ import org.hibernate.Length; import org.hibernate.LockMode; import org.hibernate.LockOptions; -import org.hibernate.PessimisticLockException; import org.hibernate.QueryTimeoutException; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.boot.model.TypeContributions; @@ -46,6 +45,7 @@ import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.exception.LockAcquisitionException; +import org.hibernate.exception.LockTimeoutException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor; import org.hibernate.exception.spi.ViolatedConstraintNameExtractor; @@ -1041,13 +1041,13 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() { final String sqlState = extractSqlState( sqlException ); if ( sqlState != null ) { switch ( sqlState ) { - case "40P01": - // DEADLOCK DETECTED + case "40P01": // DEADLOCK DETECTED return new LockAcquisitionException( message, sqlException, sql ); - case "55P03": - // LOCK NOT AVAILABLE - return new PessimisticLockException( message, sqlException, sql ); - case "57014": + case "55P03": // LOCK NOT AVAILABLE + //TODO: should we check that the message is "canceling statement due to lock timeout" + // and return LockAcquisitionException if it is not? + return new LockTimeoutException( message, sqlException, sql ); + case "57014": // QUERY CANCELLED return new QueryTimeoutException( message, sqlException, sql ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/lock/OptimisticEntityLockException.java b/hibernate-core/src/main/java/org/hibernate/dialect/lock/OptimisticEntityLockException.java index 1b667b174a4d..3ec9a8fd4675 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/lock/OptimisticEntityLockException.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/lock/OptimisticEntityLockException.java @@ -8,6 +8,8 @@ * Represents an error trying to apply an optimistic {@link LockingStrategy} to an entity * * @author Steve Ebersole + * + * @see jakarta.persistence.OptimisticLockException */ public class OptimisticEntityLockException extends LockingStrategyException { /** diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticEntityLockException.java b/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticEntityLockException.java index 5ea092606d6c..b7469e0e7b5e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticEntityLockException.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticEntityLockException.java @@ -10,6 +10,8 @@ * Represents an error trying to apply a pessimistic {@link LockingStrategy} to an entity * * @author Steve Ebersole + * + * @see jakarta.persistence.PessimisticLockException */ public class PessimisticEntityLockException extends LockingStrategyException { /** diff --git a/hibernate-core/src/main/java/org/hibernate/exception/LockAcquisitionException.java b/hibernate-core/src/main/java/org/hibernate/exception/LockAcquisitionException.java index 0de92f9c7c4d..a1e253d5f8d0 100644 --- a/hibernate-core/src/main/java/org/hibernate/exception/LockAcquisitionException.java +++ b/hibernate-core/src/main/java/org/hibernate/exception/LockAcquisitionException.java @@ -6,6 +6,7 @@ import java.sql.SQLException; +import org.hibernate.PessimisticLockException; import org.hibernate.JDBCException; /** @@ -14,7 +15,7 @@ * * @author Steve Ebersole */ -public class LockAcquisitionException extends JDBCException { +public class LockAcquisitionException extends PessimisticLockException { public LockAcquisitionException(String string, SQLException root) { super( string, root ); } diff --git a/hibernate-core/src/main/java/org/hibernate/exception/LockTimeoutException.java b/hibernate-core/src/main/java/org/hibernate/exception/LockTimeoutException.java index 53b816d78599..7a9dbebac2a7 100644 --- a/hibernate-core/src/main/java/org/hibernate/exception/LockTimeoutException.java +++ b/hibernate-core/src/main/java/org/hibernate/exception/LockTimeoutException.java @@ -16,6 +16,7 @@ * * @see org.hibernate.LockOptions#getTimeOut * @see org.hibernate.LockOptions#setTimeOut + * @see jakarta.persistence.LockTimeoutException */ public class LockTimeoutException extends LockAcquisitionException { public LockTimeoutException(String string, SQLException root) { diff --git a/hibernate-core/src/main/java/org/hibernate/exception/SnapshotIsolationException.java b/hibernate-core/src/main/java/org/hibernate/exception/SnapshotIsolationException.java new file mode 100644 index 000000000000..29b0f10c22e2 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/exception/SnapshotIsolationException.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.exception; + +import org.hibernate.Incubating; +import org.hibernate.JDBCException; + +import java.sql.SQLException; + +/** + * A {@link org.hibernate.JDBCException} indicating that a request failed due to snapshot isolation. + * This is a condition which indicates an optimistic failure. + * + * @apiNote At present, this is only used to represent {@code DB_RECORD_CHANGED} on MariaDB. + * + * @see jakarta.persistence.OptimisticLockException + */ +@Incubating +public class SnapshotIsolationException extends JDBCException { + public SnapshotIsolationException(String string, SQLException root, String sql) { + super( string, root, sql ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/exception/internal/SQLStateConversionDelegate.java b/hibernate-core/src/main/java/org/hibernate/exception/internal/SQLStateConversionDelegate.java index 0b1b9d998ad3..da51bfbec09b 100644 --- a/hibernate-core/src/main/java/org/hibernate/exception/internal/SQLStateConversionDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/exception/internal/SQLStateConversionDelegate.java @@ -7,8 +7,6 @@ import java.sql.SQLException; import org.hibernate.JDBCException; -import org.hibernate.PessimisticLockException; -import org.hibernate.QueryTimeoutException; import org.hibernate.exception.AuthException; import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.ConstraintViolationException.ConstraintKind; @@ -22,7 +20,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import static org.hibernate.internal.util.JdbcExceptionHelper.determineSqlStateClassCode; -import static org.hibernate.internal.util.JdbcExceptionHelper.extractErrorCode; import static org.hibernate.internal.util.JdbcExceptionHelper.extractSqlState; /** @@ -53,17 +50,6 @@ public SQLStateConversionDelegate(ConversionContext conversionContext) { return new AuthException( message, sqlException, sql ); case "40001": return new LockAcquisitionException( message, sqlException, sql ); - case "40XL1", "40XL2": - // Derby "A lock could not be obtained within the time requested." - return new PessimisticLockException( message, sqlException, sql ); - case "70100": - // MySQL Query execution was interrupted - return new QueryTimeoutException( message, sqlException, sql ); - case "72000": - if ( extractErrorCode( sqlException ) == 1013 ) { - // Oracle user requested cancel of current operation - return new QueryTimeoutException( message, sqlException, sql ); - } } switch ( determineSqlStateClassCode( sqlState ) ) { case diff --git a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java index 8d45bb658cae..a468ddade531 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java @@ -699,10 +699,6 @@ void cannotResolveNonNullableTransientDependencies( @Message(value = "The %2$s version for [%s] is no longer supported, hence certain features may not work properly. The minimum supported version is %3$s. Check the community dialects project for available legacy versions.", id = 511) void unsupportedDatabaseVersion(String databaseName, String actualVersion, String minimumVersion); - @LogMessage(level = WARN) - @Message(value = "The database version version for the Cockroach Dialect could not be determined. The minimum supported version (%s) has been set instead.", id = 512) - void unableToDetermineCockroachDatabaseVersion(String minimumVersion); - @LogMessage(level = DEBUG) @Message(value = "Unable to create the ReflectionOptimizer for [%s]: %s", id = 513) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/ExceptionConverterImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/ExceptionConverterImpl.java index e90f2f903389..887ba840411b 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/ExceptionConverterImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/ExceptionConverterImpl.java @@ -7,6 +7,7 @@ import java.io.Serializable; import java.sql.SQLException; +import org.hibernate.AssertionFailure; import org.hibernate.HibernateException; import org.hibernate.JDBCException; import org.hibernate.LockOptions; @@ -21,7 +22,7 @@ import org.hibernate.dialect.lock.PessimisticEntityLockException; import org.hibernate.engine.spi.ExceptionConverter; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.exception.LockAcquisitionException; +import org.hibernate.exception.SnapshotIsolationException; import org.hibernate.exception.TransactionSerializationException; import org.hibernate.loader.MultipleBagFetchException; import org.hibernate.query.IllegalQueryOperationException; @@ -80,20 +81,18 @@ public RuntimeException convert(HibernateException exception, LockOptions lockOp rollbackIfNecessary( converted ); return converted; } - else if ( exception instanceof LockAcquisitionException ) { - final PersistenceException converted = wrapLockException( exception, lockOptions ); + else if ( exception instanceof org.hibernate.PessimisticLockException pessimisticLockException ) { + final PersistenceException converted = wrapLockException( pessimisticLockException, lockOptions ); rollbackIfNecessary( converted ); return converted; } - else if ( exception instanceof LockingStrategyException ) { - final PersistenceException converted = wrapLockException( exception, lockOptions ); + else if ( exception instanceof LockingStrategyException lockingStrategyException ) { + final PersistenceException converted = wrapLockException( lockingStrategyException, lockOptions ); rollbackIfNecessary( converted ); return converted; } - else if ( exception instanceof org.hibernate.PessimisticLockException ) { - final PersistenceException converted = wrapLockException( exception, lockOptions ); - rollbackIfNecessary( converted ); - return converted; + else if ( exception instanceof SnapshotIsolationException ) { + return new OptimisticLockException( exception.getMessage(), exception ); } else if ( exception instanceof org.hibernate.QueryTimeoutException ) { final QueryTimeoutException converted = new QueryTimeoutException( exception.getMessage(), exception ); @@ -202,27 +201,30 @@ protected PersistenceException wrapStaleStateException(StaleStateException excep return new OptimisticLockException( exception.getMessage(), exception ); } - protected PersistenceException wrapLockException(HibernateException exception, LockOptions lockOptions) { + protected PersistenceException wrapLockException(LockingStrategyException exception, LockOptions lockOptions) { if ( exception instanceof OptimisticEntityLockException lockException ) { return new OptimisticLockException( lockException.getMessage(), lockException, lockException.getEntity() ); } - else if ( exception instanceof org.hibernate.exception.LockTimeoutException ) { - return new LockTimeoutException( exception.getMessage(), exception, null ); - } else if ( exception instanceof PessimisticEntityLockException lockException ) { // assume lock timeout occurred if a timeout or NO WAIT was specified return lockOptions != null && lockOptions.getTimeOut() > -1 ? new LockTimeoutException( lockException.getMessage(), lockException, lockException.getEntity() ) : new PessimisticLockException( lockException.getMessage(), lockException, lockException.getEntity() ); } - else if ( exception instanceof org.hibernate.PessimisticLockException lockException ) { - // assume lock timeout occurred if a timeout or NO WAIT was specified - return lockOptions != null && lockOptions.getTimeOut() > -1 - ? new LockTimeoutException( lockException.getMessage(), lockException, null ) - : new PessimisticLockException( lockException.getMessage(), lockException, null ); + else { + throw new AssertionFailure( "Unrecognized exception type" ); + } + } + + protected PersistenceException wrapLockException(org.hibernate.PessimisticLockException exception, LockOptions lockOptions) { + if ( exception instanceof org.hibernate.exception.LockTimeoutException ) { + return new LockTimeoutException( exception.getMessage(), exception ); } else { - return new OptimisticLockException( exception ); + // assume lock timeout occurred if a timeout or NO WAIT was specified + return lockOptions != null && lockOptions.getTimeOut() > -1 + ? new LockTimeoutException( exception.getMessage(), exception ) + : new PessimisticLockException( exception.getMessage(), exception ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/batch/BatchUpdateAndVersionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/batch/BatchUpdateAndVersionTest.java index 51261401562f..a761bf59298b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/batch/BatchUpdateAndVersionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/batch/BatchUpdateAndVersionTest.java @@ -14,7 +14,7 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.MariaDBDialect; -import org.hibernate.exception.LockAcquisitionException; +import org.hibernate.exception.SnapshotIsolationException; import org.hibernate.exception.TransactionSerializationException; import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.DomainModel; @@ -141,7 +141,7 @@ public void testFailedUpdate(SessionFactoryScope scope) { catch (OptimisticLockException ole) { if (getDialect() instanceof MariaDBDialect && getDialect().getVersion().isAfter( 11, 6, 2 )) { // if @@innodb_snapshot_isolation is set, database throw an exception if record is not available anymore - assertTrue( ole.getCause() instanceof LockAcquisitionException ); + assertTrue( ole.getCause() instanceof SnapshotIsolationException ); } else { assertTrue( ole.getCause() instanceof StaleObjectStateException ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/CockroachDialectVersionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/CockroachDialectVersionTest.java index 87c71d85b881..c9a0384b5c4d 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/CockroachDialectVersionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/CockroachDialectVersionTest.java @@ -12,7 +12,6 @@ import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.logger.Triggerable; import org.hibernate.testing.orm.logger.LoggerInspectionExtension; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -46,35 +45,7 @@ public void setUp() { @Test @JiraKey(value = "HHH-15511") public void testCockroachDialectVersionParsing() { - String failMsg = "HHH000511: The database version version for the Cockroach Dialect could not be determined ... should have been logged"; - - CockroachDBTestDialect testDialect = new CockroachDBTestDialect( null ); - Assertions.assertTrue( triggerable.wasTriggered(), failMsg); - DatabaseVersion dv = testDialect.getVersion(); - assertNotNull( dv ); - assertEquals( testDialect.getMinimumVersion().getDatabaseMajorVersion(), dv.getMajor() ); - assertEquals( testDialect.getMinimumVersion().getDatabaseMinorVersion(), dv.getMinor() ); - assertEquals( testDialect.getMinimumVersion().getDatabaseMicroVersion(), dv.getMicro() ); - triggerable.reset(); - - testDialect = new CockroachDBTestDialect( "" ); - Assertions.assertTrue( triggerable.wasTriggered(), failMsg); - dv = testDialect.getVersion(); - assertNotNull( dv ); - assertEquals( testDialect.getMinimumVersion().getDatabaseMajorVersion(), dv.getMajor() ); - assertEquals( testDialect.getMinimumVersion().getDatabaseMinorVersion(), dv.getMinor() ); - assertEquals( testDialect.getMinimumVersion().getDatabaseMicroVersion(), dv.getMicro() ); - triggerable.reset(); - - testDialect = new CockroachDBTestDialect( "Some version lacking string" ); - Assertions.assertTrue( triggerable.wasTriggered(), failMsg); - dv = testDialect.getVersion(); - assertNotNull( dv ); - assertEquals( testDialect.getMinimumVersion().getDatabaseMajorVersion(), dv.getMajor() ); - assertEquals( testDialect.getMinimumVersion().getDatabaseMinorVersion(), dv.getMinor() ); - assertEquals( testDialect.getMinimumVersion().getDatabaseMicroVersion(), dv.getMicro() ); - triggerable.reset(); - + DatabaseVersion dv; // using a fictitious major version, to avoid minimum version warnings Dialect dialect = new CockroachDBTestDialect( "CockroachDB CCL v99.2.10 (x86_64-unknown-linux-gnu, built 2022/05/02 17:38:58, go1.16.6)" ); diff --git a/migration-guide.adoc b/migration-guide.adoc index 44c9a90fdad5..a2cb5710167f 100644 --- a/migration-guide.adoc +++ b/migration-guide.adoc @@ -225,6 +225,14 @@ All such cases though are already controllable by the application. The effect can also often be mitigated using Hibernate's bytecode-based laziness (possibly combined with `@ConcreteProxy`). +[[jdbc-exceptions]] +=== JDBC exception interpretation + +Hibernate now does a better and more consistent job of interpreting database-specific error codes in ``JDBCException``s and translating to subtypes of `PersistenceException`. +In particular, interpretation of integrity constraint violations was improved significantly. + +Also, `LockAcquisitionException` now extends `PessimisticLockException`. + [[misc-api]] === Miscellaneous