Merge branch '6.0.x'

# Conflicts:
#	spring-jdbc/src/main/java/org/springframework/jdbc/support/AbstractFallbackSQLExceptionTranslator.java
This commit is contained in:
Juergen Hoeller
2023-07-14 14:38:24 +02:00
7 changed files with 81 additions and 56 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -80,10 +80,11 @@ public abstract class JdbcAccessor implements InitializingBean {
}
/**
* Specify the database product name for the DataSource that this accessor uses.
* This allows to initialize an SQLErrorCodeSQLExceptionTranslator without
* obtaining a Connection from the DataSource to get the meta-data.
* Specify the database product name for the {@code DataSource} that this accessor uses.
* This allows for initializing a {@link SQLErrorCodeSQLExceptionTranslator} without
* obtaining a {@code Connection} from the {@code DataSource} to get the meta-data.
* @param dbName the database product name that identifies the error codes entry
* @see #setExceptionTranslator
* @see SQLErrorCodeSQLExceptionTranslator#setDatabaseProductName
* @see java.sql.DatabaseMetaData#getDatabaseProductName()
*/
@@ -98,22 +99,20 @@ public abstract class JdbcAccessor implements InitializingBean {
/**
* Set the exception translator for this instance.
* <p>If no custom translator is provided, a default
* {@link SQLErrorCodeSQLExceptionTranslator} is used
* which examines the SQLException's vendor-specific error code.
* <p>A {@link SQLErrorCodeSQLExceptionTranslator} used by default if a user-provided
* `sql-error-codes.xml` file has been found in the root of the classpath. Otherwise,
* {@link SQLExceptionSubclassTranslator} serves as the default translator as of 6.0.
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
* @see org.springframework.jdbc.support.SQLExceptionSubclassTranslator
*/
public void setExceptionTranslator(SQLExceptionTranslator exceptionTranslator) {
this.exceptionTranslator = exceptionTranslator;
}
/**
* Return the exception translator for this instance.
* <p>Creates a default {@link SQLErrorCodeSQLExceptionTranslator}
* for the specified DataSource if none set, or a
* {@link SQLStateSQLExceptionTranslator} in case of no DataSource.
* @see #getDataSource()
* Return the exception translator to use for this instance,
* creating a default if necessary.
* @see #setExceptionTranslator
*/
public SQLExceptionTranslator getExceptionTranslator() {
SQLExceptionTranslator exceptionTranslator = this.exceptionTranslator;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,8 +59,8 @@ public class JdbcTransactionManager extends DataSourceTransactionManager {
/**
* Create a new JdbcTransactionManager instance.
* A DataSource has to be set to be able to use it.
* Create a new {@code JdbcTransactionManager} instance.
* A {@code DataSource} has to be set to be able to use it.
* @see #setDataSource
*/
public JdbcTransactionManager() {
@@ -68,7 +68,7 @@ public class JdbcTransactionManager extends DataSourceTransactionManager {
}
/**
* Create a new JdbcTransactionManager instance.
* Create a new {@code JdbcTransactionManager} instance.
* @param dataSource the JDBC DataSource to manage transactions for
*/
public JdbcTransactionManager(DataSource dataSource) {
@@ -79,13 +79,15 @@ public class JdbcTransactionManager extends DataSourceTransactionManager {
/**
* Specify the database product name for the DataSource that this transaction manager
* uses. This allows to initialize an SQLErrorCodeSQLExceptionTranslator without
* obtaining a Connection from the DataSource to get the meta-data.
* Specify the database product name for the {@code DataSource} that this
* transaction manager operates on.
* This allows for initializing a {@link SQLErrorCodeSQLExceptionTranslator} without
* obtaining a {@code Connection} from the {@code DataSource} to get the meta-data.
* @param dbName the database product name that identifies the error codes entry
* @see JdbcAccessor#setDatabaseProductName
* @see #setExceptionTranslator
* @see SQLErrorCodeSQLExceptionTranslator#setDatabaseProductName
* @see java.sql.DatabaseMetaData#getDatabaseProductName()
* @see JdbcAccessor#setDatabaseProductName
*/
public void setDatabaseProductName(String dbName) {
if (SQLErrorCodeSQLExceptionTranslator.hasUserProvidedErrorCodesFile()) {
@@ -97,22 +99,22 @@ public class JdbcTransactionManager extends DataSourceTransactionManager {
}
/**
* Set the exception translator for this instance.
* <p>If no custom translator is provided, a default
* {@link SQLErrorCodeSQLExceptionTranslator} is used
* which examines the SQLException's vendor-specific error code.
* @see JdbcAccessor#setExceptionTranslator
* Set the exception translator for this transaction manager.
* <p>A {@link SQLErrorCodeSQLExceptionTranslator} used by default if a user-provided
* `sql-error-codes.xml` file has been found in the root of the classpath. Otherwise,
* {@link SQLExceptionSubclassTranslator} serves as the default translator as of 6.0.
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
* @see org.springframework.jdbc.support.SQLExceptionSubclassTranslator
* @see JdbcAccessor#setExceptionTranslator
*/
public void setExceptionTranslator(SQLExceptionTranslator exceptionTranslator) {
this.exceptionTranslator = exceptionTranslator;
}
/**
* Return the exception translator for this instance.
* <p>Creates a default {@link SQLErrorCodeSQLExceptionTranslator}
* for the specified DataSource if none set.
* @see #getDataSource()
* Return the exception translator to use for this instance,
* creating a default if necessary.
* @see #setExceptionTranslator
*/
public SQLExceptionTranslator getExceptionTranslator() {
SQLExceptionTranslator exceptionTranslator = this.exceptionTranslator;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -51,6 +51,8 @@ import org.springframework.lang.Nullable;
* <p>Falls back to a standard {@link SQLStateSQLExceptionTranslator} if the JDBC
* driver does not actually expose JDBC 4 compliant {@code SQLException} subclasses.
*
* <p>This translator serves as the default translator as of 6.0.
*
* @author Thomas Risberg
* @author Juergen Hoeller
* @since 2.5
@@ -72,7 +74,7 @@ public class SQLExceptionSubclassTranslator extends AbstractFallbackSQLException
return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex);
}
if (ex instanceof SQLTransactionRollbackException) {
if ("40001".equals(ex.getSQLState())) {
if (SQLStateSQLExceptionTranslator.indicatesCannotAcquireLock(ex.getSQLState())) {
return new CannotAcquireLockException(buildMessage(task, sql, ex), ex);
}
return new PessimisticLockingFailureException(buildMessage(task, sql, ex), ex);

View File

@@ -39,11 +39,16 @@ import org.springframework.lang.Nullable;
* does not require special initialization (no database vendor detection, etc.).
* For more precise translation, consider {@link SQLErrorCodeSQLExceptionTranslator}.
*
* <p>This translator is commonly used as a {@link #setFallbackTranslator fallback}
* behind a primary translator such as {@link SQLErrorCodeSQLExceptionTranslator} or
* {@link SQLExceptionSubclassTranslator}.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Thomas Risberg
* @see java.sql.SQLException#getSQLState()
* @see SQLErrorCodeSQLExceptionTranslator
* @see SQLExceptionSubclassTranslator
*/
public class SQLStateSQLExceptionTranslator extends AbstractFallbackSQLExceptionTranslator {
@@ -111,7 +116,7 @@ public class SQLStateSQLExceptionTranslator extends AbstractFallbackSQLException
return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex);
}
else if (PESSIMISTIC_LOCKING_FAILURE_CODES.contains(classCode)) {
if ("40001".equals(sqlState)) {
if (indicatesCannotAcquireLock(sqlState)) {
return new CannotAcquireLockException(buildMessage(task, sql, ex), ex);
}
return new PessimisticLockingFailureException(buildMessage(task, sql, ex), ex);
@@ -148,9 +153,10 @@ public class SQLStateSQLExceptionTranslator extends AbstractFallbackSQLException
return sqlState;
}
/**
* Check whether the given SQL state (and the associated error code in case
* of a generic SQL state value) indicate a duplicate key exception:
* of a generic SQL state value) indicate a {@link DuplicateKeyException}:
* either SQL state 23505 as a specific indication, or the generic SQL state
* 23000 with well-known vendor codes (1 for Oracle, 1062 for MySQL/MariaDB,
* 2601/2627 for MS SQL Server).
@@ -163,4 +169,13 @@ public class SQLStateSQLExceptionTranslator extends AbstractFallbackSQLException
(errorCode == 1 || errorCode == 1062 || errorCode == 2601 || errorCode == 2627)));
}
/**
* Check whether the given SQL state indicates a {@link CannotAcquireLockException},
* with SQL state 40001 as a specific indication.
* @param sqlState the SQL state value
*/
static boolean indicatesCannotAcquireLock(@Nullable String sqlState) {
return "40001".equals(sqlState);
}
}