Detect SQL state 23505/40001 as DuplicateKeyException/CannotAcquireLockException
Favors PessimisticLockingFailureException over plain ConcurrencyFailureException. Deprecates CannotSerializeTransactionException and DeadlockLoserDataAccessException. Closes gh-29511 Closes gh-29675
This commit is contained in:
@@ -177,6 +177,7 @@ public class SQLErrorCodeSQLExceptionTranslator extends AbstractFallbackSQLExcep
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
@Nullable
|
||||
protected DataAccessException doTranslate(String task, @Nullable String sql, SQLException ex) {
|
||||
|
||||
@@ -30,12 +30,14 @@ import java.sql.SQLTransactionRollbackException;
|
||||
import java.sql.SQLTransientConnectionException;
|
||||
import java.sql.SQLTransientException;
|
||||
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.dao.CannotAcquireLockException;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.PermissionDeniedDataAccessException;
|
||||
import org.springframework.dao.PessimisticLockingFailureException;
|
||||
import org.springframework.dao.QueryTimeoutException;
|
||||
import org.springframework.dao.RecoverableDataAccessException;
|
||||
import org.springframework.dao.TransientDataAccessResourceException;
|
||||
@@ -69,10 +71,13 @@ public class SQLExceptionSubclassTranslator extends AbstractFallbackSQLException
|
||||
if (ex instanceof SQLTransientConnectionException) {
|
||||
return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
else if (ex instanceof SQLTransactionRollbackException) {
|
||||
return new ConcurrencyFailureException(buildMessage(task, sql, ex), ex);
|
||||
if (ex instanceof SQLTransactionRollbackException) {
|
||||
if ("40001".equals(ex.getSQLState())) {
|
||||
return new CannotAcquireLockException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
return new PessimisticLockingFailureException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
else if (ex instanceof SQLTimeoutException) {
|
||||
if (ex instanceof SQLTimeoutException) {
|
||||
return new QueryTimeoutException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
}
|
||||
@@ -80,19 +85,22 @@ public class SQLExceptionSubclassTranslator extends AbstractFallbackSQLException
|
||||
if (ex instanceof SQLNonTransientConnectionException) {
|
||||
return new DataAccessResourceFailureException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
else if (ex instanceof SQLDataException) {
|
||||
if (ex instanceof SQLDataException) {
|
||||
return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
else if (ex instanceof SQLIntegrityConstraintViolationException) {
|
||||
if (ex instanceof SQLIntegrityConstraintViolationException) {
|
||||
if ("23505".equals(ex.getSQLState())) {
|
||||
return new DuplicateKeyException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
else if (ex instanceof SQLInvalidAuthorizationSpecException) {
|
||||
if (ex instanceof SQLInvalidAuthorizationSpecException) {
|
||||
return new PermissionDeniedDataAccessException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
else if (ex instanceof SQLSyntaxErrorException) {
|
||||
if (ex instanceof SQLSyntaxErrorException) {
|
||||
return new BadSqlGrammarException(task, (sql != null ? sql : ""), ex);
|
||||
}
|
||||
else if (ex instanceof SQLFeatureNotSupportedException) {
|
||||
if (ex instanceof SQLFeatureNotSupportedException) {
|
||||
return new InvalidDataAccessApiUsageException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,12 @@ package org.springframework.jdbc.support;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.dao.CannotAcquireLockException;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.PessimisticLockingFailureException;
|
||||
import org.springframework.dao.QueryTimeoutException;
|
||||
import org.springframework.dao.TransientDataAccessResourceException;
|
||||
import org.springframework.jdbc.BadSqlGrammarException;
|
||||
@@ -77,7 +79,7 @@ public class SQLStateSQLExceptionTranslator extends AbstractFallbackSQLException
|
||||
"S1" // DB2: communication failure
|
||||
);
|
||||
|
||||
private static final Set<String> CONCURRENCY_FAILURE_CODES = Set.of(
|
||||
private static final Set<String> PESSIMISTIC_LOCKING_FAILURE_CODES = Set.of(
|
||||
"40", // Transaction rollback
|
||||
"61" // Oracle: deadlock
|
||||
);
|
||||
@@ -97,6 +99,9 @@ public class SQLStateSQLExceptionTranslator extends AbstractFallbackSQLException
|
||||
return new BadSqlGrammarException(task, (sql != null ? sql : ""), ex);
|
||||
}
|
||||
else if (DATA_INTEGRITY_VIOLATION_CODES.contains(classCode)) {
|
||||
if ("23505".equals(sqlState)) {
|
||||
return new DuplicateKeyException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
else if (DATA_ACCESS_RESOURCE_FAILURE_CODES.contains(classCode)) {
|
||||
@@ -105,8 +110,11 @@ public class SQLStateSQLExceptionTranslator extends AbstractFallbackSQLException
|
||||
else if (TRANSIENT_DATA_ACCESS_RESOURCE_CODES.contains(classCode)) {
|
||||
return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
else if (CONCURRENCY_FAILURE_CODES.contains(classCode)) {
|
||||
return new ConcurrencyFailureException(buildMessage(task, sql, ex), ex);
|
||||
else if (PESSIMISTIC_LOCKING_FAILURE_CODES.contains(classCode)) {
|
||||
if ("40001".equals(sqlState)) {
|
||||
return new CannotAcquireLockException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
return new PessimisticLockingFailureException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.jdbc.support;
|
||||
|
||||
import java.sql.SQLDataException;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -37,8 +38,8 @@ public class SQLExceptionCustomTranslatorTests {
|
||||
private static SQLErrorCodes ERROR_CODES = new SQLErrorCodes();
|
||||
|
||||
static {
|
||||
ERROR_CODES.setBadSqlGrammarCodes(new String[] { "1" });
|
||||
ERROR_CODES.setDataAccessResourceFailureCodes(new String[] { "2" });
|
||||
ERROR_CODES.setBadSqlGrammarCodes("1");
|
||||
ERROR_CODES.setDataAccessResourceFailureCodes("2");
|
||||
ERROR_CODES.setCustomSqlExceptionTranslatorClass(CustomSqlExceptionTranslator.class);
|
||||
}
|
||||
|
||||
@@ -47,7 +48,7 @@ public class SQLExceptionCustomTranslatorTests {
|
||||
|
||||
@Test
|
||||
public void badSqlGrammarException() {
|
||||
SQLException badSqlGrammarExceptionEx = SQLExceptionSubclassFactory.newSQLDataException("", "", 1);
|
||||
SQLException badSqlGrammarExceptionEx = new SQLDataException("", "", 1);
|
||||
DataAccessException dae = sext.translate("task", "SQL", badSqlGrammarExceptionEx);
|
||||
assertThat(dae.getCause()).isEqualTo(badSqlGrammarExceptionEx);
|
||||
assertThat(dae).isInstanceOf(BadSqlGrammarException.class);
|
||||
@@ -55,7 +56,7 @@ public class SQLExceptionCustomTranslatorTests {
|
||||
|
||||
@Test
|
||||
public void dataAccessResourceException() {
|
||||
SQLException dataAccessResourceEx = SQLExceptionSubclassFactory.newSQLDataException("", "", 2);
|
||||
SQLException dataAccessResourceEx = new SQLDataException("", "", 2);
|
||||
DataAccessException dae = sext.translate("task", "SQL", dataAccessResourceEx);
|
||||
assertThat(dae.getCause()).isEqualTo(dataAccessResourceEx);
|
||||
assertThat(dae).isInstanceOf(TransientDataAccessResourceException.class);
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.support;
|
||||
|
||||
import java.sql.SQLDataException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.sql.SQLIntegrityConstraintViolationException;
|
||||
import java.sql.SQLInvalidAuthorizationSpecException;
|
||||
import java.sql.SQLNonTransientConnectionException;
|
||||
import java.sql.SQLRecoverableException;
|
||||
import java.sql.SQLSyntaxErrorException;
|
||||
import java.sql.SQLTimeoutException;
|
||||
import java.sql.SQLTransactionRollbackException;
|
||||
import java.sql.SQLTransientConnectionException;
|
||||
|
||||
/**
|
||||
* Class to generate {@link SQLException} subclasses for testing purposes.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
*/
|
||||
public class SQLExceptionSubclassFactory {
|
||||
|
||||
public static SQLException newSQLDataException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLDataException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLFeatureNotSupportedException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLFeatureNotSupportedException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLIntegrityConstraintViolationException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLIntegrityConstraintViolationException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLInvalidAuthorizationSpecException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLInvalidAuthorizationSpecException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLNonTransientConnectionException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLNonTransientConnectionException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLSyntaxErrorException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLSyntaxErrorException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLTransactionRollbackException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLTransactionRollbackException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLTransientConnectionException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLTransientConnectionException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLTimeoutException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLTimeoutException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
public static SQLException newSQLRecoverableException(String reason, String SQLState, int vendorCode) {
|
||||
return new SQLRecoverableException(reason, SQLState, vendorCode);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -16,15 +16,28 @@
|
||||
|
||||
package org.springframework.jdbc.support;
|
||||
|
||||
import java.sql.SQLDataException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.sql.SQLIntegrityConstraintViolationException;
|
||||
import java.sql.SQLInvalidAuthorizationSpecException;
|
||||
import java.sql.SQLNonTransientConnectionException;
|
||||
import java.sql.SQLRecoverableException;
|
||||
import java.sql.SQLSyntaxErrorException;
|
||||
import java.sql.SQLTimeoutException;
|
||||
import java.sql.SQLTransactionRollbackException;
|
||||
import java.sql.SQLTransientConnectionException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.dao.CannotAcquireLockException;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.PermissionDeniedDataAccessException;
|
||||
import org.springframework.dao.PessimisticLockingFailureException;
|
||||
import org.springframework.dao.QueryTimeoutException;
|
||||
import org.springframework.dao.RecoverableDataAccessException;
|
||||
import org.springframework.dao.TransientDataAccessResourceException;
|
||||
@@ -34,78 +47,43 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class SQLExceptionSubclassTranslatorTests {
|
||||
|
||||
private static SQLErrorCodes ERROR_CODES = new SQLErrorCodes();
|
||||
@Test
|
||||
public void exceptionClassTranslation() {
|
||||
doTest(new SQLDataException("", "", 0), DataIntegrityViolationException.class);
|
||||
doTest(new SQLFeatureNotSupportedException("", "", 0), InvalidDataAccessApiUsageException.class);
|
||||
doTest(new SQLIntegrityConstraintViolationException("", "", 0), DataIntegrityViolationException.class);
|
||||
doTest(new SQLIntegrityConstraintViolationException("", "23505", 0), DuplicateKeyException.class);
|
||||
doTest(new SQLInvalidAuthorizationSpecException("", "", 0), PermissionDeniedDataAccessException.class);
|
||||
doTest(new SQLNonTransientConnectionException("", "", 0), DataAccessResourceFailureException.class);
|
||||
doTest(new SQLRecoverableException("", "", 0), RecoverableDataAccessException.class);
|
||||
doTest(new SQLSyntaxErrorException("", "", 0), BadSqlGrammarException.class);
|
||||
doTest(new SQLTimeoutException("", "", 0), QueryTimeoutException.class);
|
||||
doTest(new SQLTransactionRollbackException("", "", 0), PessimisticLockingFailureException.class);
|
||||
doTest(new SQLTransactionRollbackException("", "40001", 0), CannotAcquireLockException.class);
|
||||
doTest(new SQLTransientConnectionException("", "", 0), TransientDataAccessResourceException.class);
|
||||
}
|
||||
|
||||
static {
|
||||
ERROR_CODES.setBadSqlGrammarCodes("1");
|
||||
@Test
|
||||
public void fallbackStateTranslation() {
|
||||
// Test fallback. We assume that no database will ever return this error code,
|
||||
// but 07xxx will be bad grammar picked up by the fallback SQLState translator
|
||||
doTest(new SQLException("", "07xxx", 666666666), BadSqlGrammarException.class);
|
||||
// and 08xxx will be data resource failure (non-transient) picked up by the fallback SQLState translator
|
||||
doTest(new SQLException("", "08xxx", 666666666), DataAccessResourceFailureException.class);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void errorCodeTranslation() {
|
||||
SQLExceptionTranslator sext = new SQLErrorCodeSQLExceptionTranslator(ERROR_CODES);
|
||||
private void doTest(SQLException ex, Class<?> dataAccessExceptionType) {
|
||||
SQLExceptionTranslator translator = new SQLExceptionSubclassTranslator();
|
||||
DataAccessException dax = translator.translate("task", "SQL", ex);
|
||||
|
||||
SQLException dataIntegrityViolationEx = SQLExceptionSubclassFactory.newSQLDataException("", "", 0);
|
||||
DataIntegrityViolationException divex = (DataIntegrityViolationException) sext.translate("task", "SQL", dataIntegrityViolationEx);
|
||||
assertThat(divex.getCause()).isEqualTo(dataIntegrityViolationEx);
|
||||
|
||||
SQLException featureNotSupEx = SQLExceptionSubclassFactory.newSQLFeatureNotSupportedException("", "", 0);
|
||||
InvalidDataAccessApiUsageException idaex = (InvalidDataAccessApiUsageException) sext.translate("task", "SQL", featureNotSupEx);
|
||||
assertThat(idaex.getCause()).isEqualTo(featureNotSupEx);
|
||||
|
||||
SQLException dataIntegrityViolationEx2 = SQLExceptionSubclassFactory.newSQLIntegrityConstraintViolationException("", "", 0);
|
||||
DataIntegrityViolationException divex2 = (DataIntegrityViolationException) sext.translate("task", "SQL", dataIntegrityViolationEx2);
|
||||
assertThat(divex2.getCause()).isEqualTo(dataIntegrityViolationEx2);
|
||||
|
||||
SQLException permissionDeniedEx = SQLExceptionSubclassFactory.newSQLInvalidAuthorizationSpecException("", "", 0);
|
||||
PermissionDeniedDataAccessException pdaex = (PermissionDeniedDataAccessException) sext.translate("task", "SQL", permissionDeniedEx);
|
||||
assertThat(pdaex.getCause()).isEqualTo(permissionDeniedEx);
|
||||
|
||||
SQLException dataAccessResourceEx = SQLExceptionSubclassFactory.newSQLNonTransientConnectionException("", "", 0);
|
||||
DataAccessResourceFailureException darex = (DataAccessResourceFailureException) sext.translate("task", "SQL", dataAccessResourceEx);
|
||||
assertThat(darex.getCause()).isEqualTo(dataAccessResourceEx);
|
||||
|
||||
SQLException badSqlEx2 = SQLExceptionSubclassFactory.newSQLSyntaxErrorException("", "", 0);
|
||||
BadSqlGrammarException bsgex2 = (BadSqlGrammarException) sext.translate("task", "SQL2", badSqlEx2);
|
||||
assertThat(bsgex2.getSql()).isEqualTo("SQL2");
|
||||
assertThat((Object) bsgex2.getSQLException()).isEqualTo(badSqlEx2);
|
||||
|
||||
SQLException tranRollbackEx = SQLExceptionSubclassFactory.newSQLTransactionRollbackException("", "", 0);
|
||||
ConcurrencyFailureException cfex = (ConcurrencyFailureException) sext.translate("task", "SQL", tranRollbackEx);
|
||||
assertThat(cfex.getCause()).isEqualTo(tranRollbackEx);
|
||||
|
||||
SQLException transientConnEx = SQLExceptionSubclassFactory.newSQLTransientConnectionException("", "", 0);
|
||||
TransientDataAccessResourceException tdarex = (TransientDataAccessResourceException) sext.translate("task", "SQL", transientConnEx);
|
||||
assertThat(tdarex.getCause()).isEqualTo(transientConnEx);
|
||||
|
||||
SQLException transientConnEx2 = SQLExceptionSubclassFactory.newSQLTimeoutException("", "", 0);
|
||||
QueryTimeoutException tdarex2 = (QueryTimeoutException) sext.translate("task", "SQL", transientConnEx2);
|
||||
assertThat(tdarex2.getCause()).isEqualTo(transientConnEx2);
|
||||
|
||||
SQLException recoverableEx = SQLExceptionSubclassFactory.newSQLRecoverableException("", "", 0);
|
||||
RecoverableDataAccessException rdaex2 = (RecoverableDataAccessException) sext.translate("task", "SQL", recoverableEx);
|
||||
assertThat(rdaex2.getCause()).isEqualTo(recoverableEx);
|
||||
|
||||
// Test classic error code translation. We should move there next if the exception we pass in is not one
|
||||
// of the new subclasses.
|
||||
SQLException sexEct = new SQLException("", "", 1);
|
||||
BadSqlGrammarException bsgEct = (BadSqlGrammarException) sext.translate("task", "SQL-ECT", sexEct);
|
||||
assertThat(bsgEct.getSql()).isEqualTo("SQL-ECT");
|
||||
assertThat((Object) bsgEct.getSQLException()).isEqualTo(sexEct);
|
||||
|
||||
// Test fallback. We assume that no database will ever return this error code,
|
||||
// but 07xxx will be bad grammar picked up by the fallback SQLState translator
|
||||
SQLException sexFbt = new SQLException("", "07xxx", 666666666);
|
||||
BadSqlGrammarException bsgFbt = (BadSqlGrammarException) sext.translate("task", "SQL-FBT", sexFbt);
|
||||
assertThat(bsgFbt.getSql()).isEqualTo("SQL-FBT");
|
||||
assertThat((Object) bsgFbt.getSQLException()).isEqualTo(sexFbt);
|
||||
// and 08xxx will be data resource failure (non-transient) picked up by the fallback SQLState translator
|
||||
SQLException sexFbt2 = new SQLException("", "08xxx", 666666666);
|
||||
DataAccessResourceFailureException darfFbt = (DataAccessResourceFailureException) sext.translate("task", "SQL-FBT2", sexFbt2);
|
||||
assertThat(darfFbt.getCause()).isEqualTo(sexFbt2);
|
||||
assertThat(dax).as("Specific translation must not result in null").isNotNull();
|
||||
assertThat(dax).as("Wrong DataAccessException type returned").isExactlyInstanceOf(dataAccessExceptionType);
|
||||
assertThat(dax.getCause()).as("The exact same original SQLException must be preserved").isSameAs(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.support;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.jdbc.BadSqlGrammarException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Rod Johnson
|
||||
* @since 13-Jan-03
|
||||
*/
|
||||
public class SQLStateExceptionTranslatorTests {
|
||||
|
||||
private static final String sql = "SELECT FOO FROM BAR";
|
||||
|
||||
private final SQLStateSQLExceptionTranslator trans = new SQLStateSQLExceptionTranslator();
|
||||
|
||||
// ALSO CHECK CHAIN of SQLExceptions!?
|
||||
// also allow chain of translators? default if can't do specific?
|
||||
|
||||
@Test
|
||||
public void badSqlGrammar() {
|
||||
SQLException sex = new SQLException("Message", "42001", 1);
|
||||
try {
|
||||
throw this.trans.translate("task", sql, sex);
|
||||
}
|
||||
catch (BadSqlGrammarException ex) {
|
||||
// OK
|
||||
assertThat(sql.equals(ex.getSql())).as("SQL is correct").isTrue();
|
||||
assertThat(sex.equals(ex.getSQLException())).as("Exception matches").isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidSqlStateCode() {
|
||||
SQLException sex = new SQLException("Message", "NO SUCH CODE", 1);
|
||||
assertThat(this.trans.translate("task", sql, sex)).isNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* PostgreSQL can return null.
|
||||
* SAP DB can apparently return empty SQL code.
|
||||
* Bug 729170
|
||||
*/
|
||||
@Test
|
||||
public void malformedSqlStateCodes() {
|
||||
SQLException sex = new SQLException("Message", null, 1);
|
||||
assertThat(this.trans.translate("task", sql, sex)).isNull();
|
||||
|
||||
sex = new SQLException("Message", "", 1);
|
||||
assertThat(this.trans.translate("task", sql, sex)).isNull();
|
||||
|
||||
// One char's not allowed
|
||||
sex = new SQLException("Message", "I", 1);
|
||||
assertThat(this.trans.translate("task", sql, sex)).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -20,12 +20,15 @@ import java.sql.SQLException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.dao.CannotAcquireLockException;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.PessimisticLockingFailureException;
|
||||
import org.springframework.dao.TransientDataAccessResourceException;
|
||||
import org.springframework.jdbc.BadSqlGrammarException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
@@ -37,58 +40,83 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
*/
|
||||
public class SQLStateSQLExceptionTranslatorTests {
|
||||
|
||||
private static final String REASON = "The game is afoot!";
|
||||
|
||||
private static final String TASK = "Counting sheep... yawn.";
|
||||
|
||||
private static final String SQL = "select count(0) from t_sheep where over_fence = ... yawn... 1";
|
||||
|
||||
|
||||
@Test
|
||||
public void testTranslateNullException() {
|
||||
public void translateNullException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() ->
|
||||
new SQLStateSQLExceptionTranslator().translate("", "", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTranslateBadSqlGrammar() {
|
||||
public void translateBadSqlGrammar() {
|
||||
doTest("07", BadSqlGrammarException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTranslateDataIntegrityViolation() {
|
||||
public void translateDataIntegrityViolation() {
|
||||
doTest("23", DataIntegrityViolationException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTranslateDataAccessResourceFailure() {
|
||||
public void translateDuplicateKey() {
|
||||
doTest("23505", DuplicateKeyException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void translateDataAccessResourceFailure() {
|
||||
doTest("53", DataAccessResourceFailureException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTranslateTransientDataAccessResourceFailure() {
|
||||
public void translateTransientDataAccessResourceFailure() {
|
||||
doTest("S1", TransientDataAccessResourceException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTranslateConcurrencyFailure() {
|
||||
doTest("40", ConcurrencyFailureException.class);
|
||||
public void translatePessimisticLockingFailure() {
|
||||
doTest("40", PessimisticLockingFailureException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTranslateUncategorized() {
|
||||
assertThat(new SQLStateSQLExceptionTranslator().translate("", "", new SQLException(REASON, "00000000"))).isNull();
|
||||
public void translateCannotAcquireLock() {
|
||||
doTest("40001", CannotAcquireLockException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void translateUncategorized() {
|
||||
doTest("00000000", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidSqlStateCode() {
|
||||
doTest("NO SUCH CODE", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* PostgreSQL can return null.
|
||||
* SAP DB can apparently return empty SQL code.
|
||||
* Bug 729170
|
||||
*/
|
||||
@Test
|
||||
public void malformedSqlStateCodes() {
|
||||
doTest(null, null);
|
||||
doTest("", null);
|
||||
doTest("I", null);
|
||||
}
|
||||
|
||||
|
||||
private void doTest(String sqlState, Class<?> dataAccessExceptionType) {
|
||||
SQLException ex = new SQLException(REASON, sqlState);
|
||||
private void doTest(@Nullable String sqlState, @Nullable Class<?> dataAccessExceptionType) {
|
||||
SQLExceptionTranslator translator = new SQLStateSQLExceptionTranslator();
|
||||
DataAccessException dax = translator.translate(TASK, SQL, ex);
|
||||
assertThat(dax).as("Specific translation must not result in a null DataAccessException being returned.").isNotNull();
|
||||
assertThat(dax.getClass()).as("Wrong DataAccessException type returned as the result of the translation").isEqualTo(dataAccessExceptionType);
|
||||
assertThat(dax.getCause()).as("The original SQLException must be preserved in the translated DataAccessException").isNotNull();
|
||||
assertThat(dax.getCause()).as("The exact same original SQLException must be preserved in the translated DataAccessException").isSameAs(ex);
|
||||
SQLException ex = new SQLException("reason", sqlState);
|
||||
DataAccessException dax = translator.translate("task", "SQL", ex);
|
||||
|
||||
if (dataAccessExceptionType == null) {
|
||||
assertThat(dax).as("Expected translation to null").isNull();
|
||||
return;
|
||||
}
|
||||
|
||||
assertThat(dax).as("Specific translation must not result in null").isNotNull();
|
||||
assertThat(dax).as("Wrong DataAccessException type returned").isExactlyInstanceOf(dataAccessExceptionType);
|
||||
assertThat(dax.getCause()).as("The exact same original SQLException must be preserved").isSameAs(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -32,11 +32,13 @@ import io.r2dbc.spi.Wrapped;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.dao.CannotAcquireLockException;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.PermissionDeniedDataAccessException;
|
||||
import org.springframework.dao.PessimisticLockingFailureException;
|
||||
import org.springframework.dao.QueryTimeoutException;
|
||||
import org.springframework.dao.TransientDataAccessResourceException;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -215,17 +217,23 @@ public abstract class ConnectionFactoryUtils {
|
||||
return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
if (ex instanceof R2dbcRollbackException) {
|
||||
return new ConcurrencyFailureException(buildMessage(task, sql, ex), ex);
|
||||
if ("40001".equals(ex.getSqlState())) {
|
||||
return new CannotAcquireLockException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
return new PessimisticLockingFailureException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
if (ex instanceof R2dbcTimeoutException) {
|
||||
return new QueryTimeoutException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
}
|
||||
if (ex instanceof R2dbcNonTransientException) {
|
||||
else if (ex instanceof R2dbcNonTransientException) {
|
||||
if (ex instanceof R2dbcNonTransientResourceException) {
|
||||
return new DataAccessResourceFailureException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
if (ex instanceof R2dbcDataIntegrityViolationException) {
|
||||
if ("23505".equals(ex.getSqlState())) {
|
||||
return new DuplicateKeyException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex);
|
||||
}
|
||||
if (ex instanceof R2dbcPermissionDeniedException) {
|
||||
|
||||
@@ -26,10 +26,12 @@ import io.r2dbc.spi.R2dbcTimeoutException;
|
||||
import io.r2dbc.spi.R2dbcTransientResourceException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.dao.CannotAcquireLockException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.PermissionDeniedDataAccessException;
|
||||
import org.springframework.dao.PessimisticLockingFailureException;
|
||||
import org.springframework.dao.QueryTimeoutException;
|
||||
import org.springframework.dao.TransientDataAccessResourceException;
|
||||
import org.springframework.r2dbc.BadSqlGrammarException;
|
||||
@@ -41,6 +43,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* Unit tests for {@link ConnectionFactoryUtils}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class ConnectionFactoryUtilsUnitTests {
|
||||
|
||||
@@ -48,63 +51,71 @@ public class ConnectionFactoryUtilsUnitTests {
|
||||
public void shouldTranslateTransientResourceException() {
|
||||
Exception exception = ConnectionFactoryUtils.convertR2dbcException("", "",
|
||||
new R2dbcTransientResourceException(""));
|
||||
assertThat(exception).isInstanceOf(TransientDataAccessResourceException.class);
|
||||
assertThat(exception).isExactlyInstanceOf(TransientDataAccessResourceException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldTranslateRollbackException() {
|
||||
Exception exception = ConnectionFactoryUtils.convertR2dbcException("", "",
|
||||
new R2dbcRollbackException());
|
||||
assertThat(exception).isInstanceOf(ConcurrencyFailureException.class);
|
||||
assertThat(exception).isExactlyInstanceOf(PessimisticLockingFailureException.class);
|
||||
|
||||
exception = ConnectionFactoryUtils.convertR2dbcException("", "",
|
||||
new R2dbcRollbackException("reason", "40001"));
|
||||
assertThat(exception).isExactlyInstanceOf(CannotAcquireLockException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldTranslateTimeoutException() {
|
||||
Exception exception = ConnectionFactoryUtils.convertR2dbcException("", "",
|
||||
new R2dbcTimeoutException());
|
||||
assertThat(exception).isInstanceOf(QueryTimeoutException.class);
|
||||
assertThat(exception).isExactlyInstanceOf(QueryTimeoutException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotTranslateUnknownExceptions() {
|
||||
Exception exception = ConnectionFactoryUtils.convertR2dbcException("", "",
|
||||
new MyTransientExceptions());
|
||||
assertThat(exception).isInstanceOf(UncategorizedR2dbcException.class);
|
||||
assertThat(exception).isExactlyInstanceOf(UncategorizedR2dbcException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldTranslateNonTransientResourceException() {
|
||||
Exception exception = ConnectionFactoryUtils.convertR2dbcException("", "",
|
||||
new R2dbcNonTransientResourceException());
|
||||
assertThat(exception).isInstanceOf(DataAccessResourceFailureException.class);
|
||||
assertThat(exception).isExactlyInstanceOf(DataAccessResourceFailureException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldTranslateIntegrityViolationException() {
|
||||
Exception exception = ConnectionFactoryUtils.convertR2dbcException("", "",
|
||||
new R2dbcDataIntegrityViolationException());
|
||||
assertThat(exception).isInstanceOf(DataIntegrityViolationException.class);
|
||||
assertThat(exception).isExactlyInstanceOf(DataIntegrityViolationException.class);
|
||||
|
||||
exception = ConnectionFactoryUtils.convertR2dbcException("", "",
|
||||
new R2dbcDataIntegrityViolationException("reason", "23505"));
|
||||
assertThat(exception).isExactlyInstanceOf(DuplicateKeyException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldTranslatePermissionDeniedException() {
|
||||
Exception exception = ConnectionFactoryUtils.convertR2dbcException("", "",
|
||||
new R2dbcPermissionDeniedException());
|
||||
assertThat(exception).isInstanceOf(PermissionDeniedDataAccessException.class);
|
||||
assertThat(exception).isExactlyInstanceOf(PermissionDeniedDataAccessException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldTranslateBadSqlGrammarException() {
|
||||
Exception exception = ConnectionFactoryUtils.convertR2dbcException("", "",
|
||||
new R2dbcBadGrammarException());
|
||||
assertThat(exception).isInstanceOf(BadSqlGrammarException.class);
|
||||
assertThat(exception).isExactlyInstanceOf(BadSqlGrammarException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void messageGeneration() {
|
||||
Exception exception = ConnectionFactoryUtils.convertR2dbcException("TASK",
|
||||
"SOME-SQL", new R2dbcTransientResourceException("MESSAGE"));
|
||||
assertThat(exception).isInstanceOf(
|
||||
assertThat(exception).isExactlyInstanceOf(
|
||||
TransientDataAccessResourceException.class).hasMessage("TASK; SQL [SOME-SQL]; MESSAGE");
|
||||
}
|
||||
|
||||
@@ -112,7 +123,7 @@ public class ConnectionFactoryUtilsUnitTests {
|
||||
public void messageGenerationNullSQL() {
|
||||
Exception exception = ConnectionFactoryUtils.convertR2dbcException("TASK", null,
|
||||
new R2dbcTransientResourceException("MESSAGE"));
|
||||
assertThat(exception).isInstanceOf(
|
||||
assertThat(exception).isExactlyInstanceOf(
|
||||
TransientDataAccessResourceException.class).hasMessage("TASK; MESSAGE");
|
||||
}
|
||||
|
||||
@@ -120,7 +131,7 @@ public class ConnectionFactoryUtilsUnitTests {
|
||||
public void messageGenerationNullMessage() {
|
||||
Exception exception = ConnectionFactoryUtils.convertR2dbcException("TASK",
|
||||
"SOME-SQL", new R2dbcTransientResourceException());
|
||||
assertThat(exception).isInstanceOf(
|
||||
assertThat(exception).isExactlyInstanceOf(
|
||||
TransientDataAccessResourceException.class).hasMessage("TASK; SQL [SOME-SQL]; null");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -20,6 +20,9 @@ package org.springframework.dao;
|
||||
* Exception thrown on failure to acquire a lock during an update,
|
||||
* for example during a "select for update" statement.
|
||||
*
|
||||
* <p>Consider handling the general {@link PessimisticLockingFailureException}
|
||||
* instead, semantically including a wider range of locking-related failures.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -20,8 +20,14 @@ package org.springframework.dao;
|
||||
* Exception thrown on failure to complete a transaction in serialized mode
|
||||
* due to update conflicts.
|
||||
*
|
||||
* <p>Consider handling the general {@link PessimisticLockingFailureException}
|
||||
* instead, semantically including a wider range of locking-related failures.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @deprecated as of 6.0.3, in favor of
|
||||
* {@link PessimisticLockingFailureException}/{@link CannotAcquireLockException}
|
||||
*/
|
||||
@Deprecated(since = "6.0.3")
|
||||
@SuppressWarnings("serial")
|
||||
public class CannotSerializeTransactionException extends PessimisticLockingFailureException {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -28,7 +28,9 @@ package org.springframework.dao;
|
||||
* to keep the original data access exception, if any.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @deprecated as of 6.0.3 since it is not in use within core JDBC/ORM support
|
||||
*/
|
||||
@Deprecated(since = "6.0.3")
|
||||
@SuppressWarnings("serial")
|
||||
public class CleanupFailureDataAccessException extends NonTransientDataAccessException {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -19,17 +19,15 @@ package org.springframework.dao;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Exception thrown on concurrency failure.
|
||||
* Exception thrown on various data access concurrency failures.
|
||||
*
|
||||
* <p>This exception should be subclassed to indicate the type of failure:
|
||||
* optimistic locking, failure to acquire lock, etc.
|
||||
* <p>This exception provides subclasses for specific types of failure,
|
||||
* in particular optimistic locking versus pessimistic locking.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 1.1
|
||||
* @see OptimisticLockingFailureException
|
||||
* @see PessimisticLockingFailureException
|
||||
* @see CannotAcquireLockException
|
||||
* @see DeadlockLoserDataAccessException
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ConcurrencyFailureException extends TransientDataAccessException {
|
||||
|
||||
@@ -19,8 +19,13 @@ package org.springframework.dao;
|
||||
/**
|
||||
* Exception thrown when an attempt to insert or update data
|
||||
* results in violation of an integrity constraint. Note that this
|
||||
* is not purely a relational concept; unique primary keys are
|
||||
* required by most database types.
|
||||
* is not purely a relational concept; integrity constraints such
|
||||
* as unique primary keys are required by most database types.
|
||||
*
|
||||
* <p>Serves as a superclass for more specific exceptions, e.g.
|
||||
* {@link DuplicateKeyException}. However, it is generally
|
||||
* recommended to handle {@code DataIntegrityViolationException}
|
||||
* itself instead of relying on specific exception subclasses.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -20,8 +20,14 @@ package org.springframework.dao;
|
||||
* Generic exception thrown when the current process was
|
||||
* a deadlock loser, and its transaction rolled back.
|
||||
*
|
||||
* <p>Consider handling the general {@link PessimisticLockingFailureException}
|
||||
* instead, semantically including a wider range of locking-related failures.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @deprecated as of 6.0.3, in favor of
|
||||
* {@link PessimisticLockingFailureException}/{@link CannotAcquireLockException}
|
||||
*/
|
||||
@Deprecated(since = "6.0.3")
|
||||
@SuppressWarnings("serial")
|
||||
public class DeadlockLoserDataAccessException extends PessimisticLockingFailureException {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -22,6 +22,9 @@ package org.springframework.dao;
|
||||
* Note that this is not necessarily a purely relational concept;
|
||||
* unique primary keys are required by most database types.
|
||||
*
|
||||
* <p>Consider handling the general {@link DataIntegrityViolationException}
|
||||
* instead, semantically including a wider range of constraint violations.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -21,13 +21,13 @@ package org.springframework.dao;
|
||||
* Thrown by Spring's SQLException translation mechanism
|
||||
* if a corresponding database error is encountered.
|
||||
*
|
||||
* <p>Serves as superclass for more specific exceptions, like
|
||||
* CannotAcquireLockException and DeadlockLoserDataAccessException.
|
||||
* <p>Serves as a superclass for more specific exceptions, e.g.
|
||||
* {@link CannotAcquireLockException}. However, it is generally
|
||||
* recommended to handle {@code PessimisticLockingFailureException}
|
||||
* itself instead of relying on specific exception subclasses.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 1.2
|
||||
* @see CannotAcquireLockException
|
||||
* @see DeadlockLoserDataAccessException
|
||||
* @see OptimisticLockingFailureException
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
|
||||
Reference in New Issue
Block a user