JDBC异常SQLException的捕获与处理

最近自己在实现一个通用的ID生成器,写了个内存版,后面实现mysql的持久化器时,考虑到低侵入性,使用原生JDBC来进行编程。
有一个地方实现,想通过直接insert来插入一条数据,但如果唯一字段冲突,即表明当前数据已存在,需要提示出来,让程序能正常响应。

Connection connection = dataSource.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("insert into walnut.app_info (app_id, app_name)values(?,?);")

如上面的sql,app_id是唯一索引,那么需要捕获主键冲突异常,然后做处理。
怎么做?

SQLException是一个提供了数据库访问错误或其他错误信息的异常,我们可以通过捕获来获取异常信息。
SQLException有两个用来获取判断具体错误信息的函数:

  • getSQLState() :返回一个代码,有五位的字母和数字组成 。多数的代码由 ISO/ANSI 和 Open Group(X/Open) 标准化,但是仍然存在部分的代码由数据库提供商自行实现。
  • getErrorCode():与 SQLState 不同,错误代码是由数据库提供商自行定义的整数值。通常是底层数据库返回的实际错误码。

如果我们要捕获特定的异常来做特殊处理,则可以通过上面的两个函数来处理。但考虑到getErrorCode()更加的接近实际错误,所以我们可以通过getErrorCodel()来判断。

想起来,我们在用Spring的时候,如果要捕获主键冲突,用的是DuplicateKeyException这个异常类,该类由Spring框架内定义的。本质上底层还是用的JDBC,那么它是怎么知道什么错误码转换的DuplicateKeyException
带着这个疑问,瞄了眼它内部:通过org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator#doTranslate来将SQLException转换成它自身定义的特定异常,方便外部捕获使用。
该方法中,可看到如下代码:

//this.sqlErrorCodes 即 org.springframework.jdbc.support.SQLErrorCodes
if (Arrays.binarySearch(this.sqlErrorCodes.getDuplicateKeyCodes(), errorCode) >= 0) {
    this.logTranslation(task, sql, sqlEx, false);
    return new DuplicateKeyException(this.buildMessage(task, sql, sqlEx), sqlEx);
}

其中org.springframework.jdbc.support.SQLErrorCodes中定义了一系列的特定异常错误码。

private String[] badSqlGrammarCodes = new String[0];
private String[] invalidResultSetAccessCodes = new String[0];
private String[] duplicateKeyCodes = new String[0];
private String[] dataIntegrityViolationCodes = new String[0];
private String[] permissionDeniedCodes = new String[0];
private String[] dataAccessResourceFailureCodes = new String[0];
private String[] transientDataAccessResourceCodes = new String[0];
private String[] cannotAcquireLockCodes = new String[0];
private String[] deadlockLoserCodes = new String[0];
private String[] cannotSerializeTransactionCodes = new String[0];

那么我们怎么知道数组里面是啥?Spring定义在了哪里?全局搜一下吧,果不其然,我们通过IDEA全局搜:duplicateKeyCodes
在这里插入图片描述
sql-error-codes.xml这个文件就是Spring配置的JDBC的异常码,里面涵盖了好几种DB,我们用的mysql,就看mysql的定义。通过Spring的这个文件,我们也知道了mysql的主键冲突,返回的就是1062的错误码。

接下来就是应用到我们代码中了,参考Spring的转换实现。

public class MySqlJDBCErrorCodes {
    public static final String[] badSqlGrammarCodes = {"1054", "1064", "1146"};
    public static final String[] duplicateKeyCodes = {"1062"};
    public static final String[] dataIntegrityViolationCodes = {"630", "839", "840", "893", "1169", "1215", "1216", "1217", "1364", "1451", "1452", "1557"};
    public static final String[] dataAccessResourceFailureCodes = {"1"};
    public static final String[] cannotAcquireLockCodes = {"1205"};
    public static final String[] deadlockLoserCodes = {"1213"};

    static {
        Arrays.sort(badSqlGrammarCodes);
        Arrays.sort(duplicateKeyCodes);
        Arrays.sort(dataIntegrityViolationCodes);
        Arrays.sort(dataAccessResourceFailureCodes);
        Arrays.sort(cannotAcquireLockCodes);
        Arrays.sort(deadlockLoserCodes);
    }
}

----
//示例
try {
   preparedStatement.executeUpdate();
} catch (SQLException sqlException) {
    String errorCode = Integer.toString(sqlException.getErrorCode());
    if (Arrays.binarySearch(MySqlJDBCErrorCodes.duplicateKeyCodes, errorCode) >= 0) {
        throw new DuplicateKeyException(String.format("[appid=%s] is exist!", input.getAppId()));
    }
    throw sqlException;
}

以上,就是我用JDBC编程的一段小经历,通过借鉴Spring是怎么做的异常转换,来取得自己需要的实现,做个记录望能起到帮助。

来个传送门:SQLSTATE各种状态码

  • 8
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值