捕获重复条目异常
Posted
技术标签:
【中文标题】捕获重复条目异常【英文标题】:Catch duplicate entry Exception 【发布时间】:2015-02-19 09:01:09 【问题描述】:我怎样才能捕捉到这个异常:
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
Duplicate entry '22-85' for key 'ID_CONTACT'
【问题讨论】:
最好解决导致此异常的问题 这不是问题,但使用 Web 应用程序,用户可以更改 http 请求参数,我想确保一切正常,所以我想添加这一层安全性。 但正如您从堆栈跟踪中看到的那样,在插入期间您违反了约束,最好在将数据发送到数据库之前先验证数据。如果您真的想要,您显然可以捕获异常,但我更喜欢更清洁的解决方案 最干净的解决方案是将用户重定向到一些通用的网络错误页面,该页面不显示异常跟踪(显然)但会提醒系统所有者。比尝试处理这些特殊攻击案例要好得多... 但是你怎么知道它是重复条目异常。异常表示违反约束。如果是另一个约束呢? 【参考方案1】:我用的是spring,所以我们通过org.springframework.dao.DataIntegrityViolationException
解决它
try
ao_history_repository.save(new AoHistory(..));
catch (DataIntegrityViolationException e)
System.out.println("history already exist");
但正如@KevinGuancheDarias 提到的那样:
请注意,虽然这有效。 我建议通过以下方式解决问题 在保存之前发出 findBy ,因为这很混乱,我认为这是 不保证它会在未来的版本中工作,甚至可能会破坏 没有通知。
【讨论】:
这在我的项目中对我不起作用我不知道为什么,但是我的 spring 从存储库中抛出了其他异常,请查看我的答案以获取更多信息 对于遇到此答案的任何人,请注意具有多个实例的环境中答案底部的建议。如果我没记错的话,我很可能是这样,如果您的消费服务运行多个实例(例如带有自动缩放组的 AWS EC2),那么您可能会遇到竞争条件并最终导致数据库约束违规抛出。即,findBy
响应返回“未找到”,但另一个实例在 post-findBy
逻辑可以持久化之前持久化了该对象。【参考方案2】:
在我的 Spring 项目中,抛出的异常是 org.springframework.orm.jpa.JpaSystemException: org.hibernate.exception.ConstraintViolationException: could not execute statement; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
。
所以在调试后我有一个父 JpaSystemException
有一个原因 PersistenceException
并且有一个原因 ConstraintViolationException
,最后一个有数据库特定的异常,但我最终捕获了 ConstraintViolationException
public static boolean isSqlDuplicatedKey(Exception e)
return e.getCause() != null && e.getCause().getCause() != null
&& ConstraintViolationException.class.isInstance(e.getCause().getCause());
// ....
try
someRepository.save(some);
catch (JpaSystemException e)
if (ExceptionUtilService.isSqlDuplicatedKey(e))
// Do something to handle it
else
throw e;
请注意,虽然这有效。 我建议通过在保存之前发出 findBy 来解决问题,因为这很麻烦,而且我认为不保证它会在未来的版本中正常工作,甚至可能会在没有通知的情况下中断。
【讨论】:
【参考方案3】:vendorCode 2601
用于unique index constraint
违反,因此您可以通过e.getErrorCode() == 2601
检查 SQLException cewndorCode。示例代码:
try
ao_history_repository.save(new AoHistory(..));
catch (SQLException e)
if (e.getErrorCode() == 2601)
System.out.println("handle duplicate index error here!");
else
System.out.println("handle other error code here!");
【讨论】:
能否提供相关文档链接,方便用户查看其他错误码?【参考方案4】:看Spring框架source code 查看 spring JDBC 错误解决代码。
org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator#doTranslate
else if (Arrays.binarySearch(this.sqlErrorCodes.getDuplicateKeyCodes(), errorCode) >= 0)
logTranslation(task, sql, sqlEx, false); return new DuplicateKeyException(buildMessage(task, sql, sqlEx), sqlEx);
您可以通过多种方式找到不同的异常翻译器:
从您的数据库中弹簧加载元数据/错误代码 - 一位翻译器 Spring 无法连接到 db - 另一个 Hibernate JPA 可能有不同的翻译器因此,重复行为可能会从 DuplicateKeyException 变为 DataIntegrityViolationException。
【讨论】:
【参考方案5】:我同意,但我们在我的 Spring 应用程序中有这样的东西:- RequestValidationException/MessageConstants 是自定义的:
import org.springframework.dao.DuplicateKeyException;
|
|
|
catch (Exception exception)
if(exception instanceof DuplicateKeyException)
logger.error("exception as duplicate Name Found: " + exception.getMessage());
throw new RequestValidationException(MessageConstants.DUPLICATE_NAME_FOUND_ERROR_CD, MessageConstants.DUPLICATE_NAME_FOUND_ERROR_MSG);
else
logger.error("exception on update: " + exception.getMessage());
throw exception;
【讨论】:
在我的情况下,异常 instanceof DuplicateKeyException 永远不会进入 if 循环。为什么? @PAA:你能分享堆栈跟踪吗?我的意思是你得到了什么样的异常,你到底在用什么进行数据库事务。【参考方案6】:A - 详细记录异常
这是我用来记录 SQL 异常的内容,以便我可以确定要捕获什么;
private static void handleSQLError(SQLException e) throws SQLException
log.info("SQL Error Type : " + e.getClass().getName());
log.info("Error Message : " + e.getMessage());
log.info("Error Code : " + e.getErrorCode());
log.info("SQL State : " + e.getSQLState());
throw e;
这是示例输出;
2018 Nis 05 11:20:32,248 INFO MySQLUtil: SQL Error Type : com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException
2018 Nis 05 11:20:32,248 INFO MySQLUtil: Error Message : Duplicate entry 'test2 CAMT052' for key 'customer_file_customer_file_name_idxu'
2018 Nis 05 11:20:32,249 INFO MySQLUtil: Error Code : 1062
2018 Nis 05 11:20:32,249 INFO MySQLUtil: SQL State : 23000
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'test' for key 'customer_file_customer_file_name_idxu'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
B - 捕获异常并检查参数
要捕获重复键异常,我们需要捕获特定的类,即MySQLIntegrityConstraintViolationException
。以下参数也必须匹配;
SQL State : 23000
所以我使用以下块来捕获重复条目;
try
dbUtil.persistEntry(entry);
catch (SQLException e)
if(e instanceof MySQLIntegrityConstraintViolationException)
if(e.getSQLState().equals("23000"))
if(e.getMessage().contains("Duplicate"))
isDuplicateEntryError = true;
【讨论】:
如果有人(如我)来到这里:SQL 状态不是重复输入错误的直接指标。如果您查看 MariaDB 的官方错误文档(它们有共享错误;mariadb.com/kb/en/library/mariadb-error-codes),您会看到导致该状态的多个错误。这里更重要的信息是错误代码,因为它直接映射到错误。 (在某些情况下,您必须检查多个代码,例如我发现死锁可以返回 1213 和 1205)。 TLDR:更好地检查错误代码而不是 sql 状态【参考方案7】:我使用弹簧。 所以抓住 org.springframework.dao.DuplicateKeyException
try
...
catch (DuplicateKeyException dke)
...
【讨论】:
【参考方案8】:以下代码适用于我:
try
requete.executeUpdate();
catch (final ConstraintViolationException e)
【讨论】:
【参考方案9】:捕获 SQLIntegrityConstraintViolationException,如果您使用的是 Java 1.6+
例如
try
ps.executeUpdate("INSERT INTO ...");
catch (SQLIntegrityConstraintViolationException e)
// Duplicate entry
catch (SQLException e)
// Other SQL Exception
或
try
ps.executeUpdate("INSERT INTO ...");
catch (SQLException e)
if (e instanceof SQLIntegrityConstraintViolationException)
// Duplicate entry
else
// Other SQL Exception
【讨论】:
Unreachable catch block for SQLIntegrityConstraintViolationException. This exception is never thrown from the try statement body
@Youssef,你的 mysql-connector-java 的版本是多少?您尝试更新的 SQL 是什么?
需要捕获 SQLException。然后您可以检测它是否是 SQLIntegrityConstraintViolationException。请注意,MySQLIntegrityConstraintViolationException 是一种 SQLIntegrityConstraintViolationException。以上是关于捕获重复条目异常的主要内容,如果未能解决你的问题,请参考以下文章