Skip to content

异常处理 ​

ActiveRecordException ​


1、背景简介 ​

在使用 Java-DB(即 LitongJava ActiveRecord 框架)操作数据库时,当执行增删改查操作失败,框架会抛出 ActiveRecordException。出于安全考虑,该异常默认不会将完整的 SQL 语句及参数打印到控制台,而是将它们保存在异常对象内部,避免敏感信息泄露。


2、异常捕获与日志记录 ​

为了既能保证安全性,又能方便排查问题,需要在捕获 ActiveRecordException 时,主动将其内部保存的 SQL 语句和参数输出到日志。示例代码如下:

java
try {
    // 执行数据库操作,例如:
    // Db.update("INSERT INTO ...", params);
} catch (Exception e) {
    if (e instanceof ActiveRecordException) {
        ActiveRecordException ae = (ActiveRecordException) e;
        // 从异常中提取 SQL 和参数,并写入错误日志
        log.error("Error: line={}, SQL=[{}], Params={}, Exception:", 
                  line, 
                  ae.getSql(), 
                  ae.getParas(), 
                  e);
    } else {
        // 对于其他类型的异常,按常规方式记录
        log.error("Error: line={}, Exception:", line, e);
    }
}
  • line:表示出错代码所在的行号或业务标识,可帮助快速定位问题发生的位置。
  • ae.getSql():获取抛出异常时执行的 SQL 语句。
  • ae.getParas():获取执行该 SQL 时所使用的参数列表。
  • e:完整的异常堆栈,包括框架内部抛出的 ActiveRecordException 及其根因。

3、日志输出示例 ​

假设在第 14 行执行 UID STORE 操作时触发异常,日志可能如下所示:

Error: line=14, SQL=[INSERT INTO mw_mail_flag (id, mail_id, flag) VALUES (?, ?, ?) ON CONFLICT (mail_id, flag) DO NOTHING;], Params=[528755689311666176, 528442583916969984, \Seen], Exception:
nexus.io.db.activerecord.ActiveRecordException: ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification
    at nexus.io.db.activerecord.DbPro.update(DbPro.java:443)
    at nexus.io.db.activerecord.DbPro.update(DbPro.java:477)
    at nexus.io.db.activerecord.Db.updateBySql(Db.java:207)
    at com.tio.mail.wing.service.MailService.storeFlags(MailService.java:273)
    at com.tio.mail.wing.service.ImapService.handleStore(ImapService.java:310)
    at com.tio.mail.wing.service.ImapService.handleUid(ImapService.java:332)
    at com.tio.mail.wing.handler.ImapServerAioHandler.handler(ImapServerAioHandler.java:123)
    …

通过上述日志,我们能够清晰地看到:

  1. 出错位置:line=14。
  2. 执行的 SQL:完整的 INSERT INTO ... 语句。
  3. 绑定参数:三个具体值 [528755689311666176, 528442583916969984, \Seen]。
  4. 异常堆栈:快速定位到底是哪个方法、哪一行代码引发的问题。

4、最佳实践建议 ​

  1. 统一异常处理

    • 将上述捕获逻辑封装到一个公共工具或基类中,所有 DAO/Service 层操作均可复用,避免重复代码。
    • 可针对不同业务场景,进一步细化日志级别(ERROR、WARN)及格式。
  2. 敏感信息屏蔽

    • 在生产环境中,若 SQL 或参数中可能包含敏感数据(如密码、用户隐私),应对敏感字段做过滤或脱敏后再记录。
  3. 告警与监控

    • 对频繁抛出 ActiveRecordException 的场景设置告警,及时发现和修复数据库性能或语法问题。
    • 将关键异常推送至监控平台(如 Sentry、Prometheus + Alertmanager)以便实时跟踪。
  4. 异常链处理

    • 如果 ActiveRecordException 的根因是底层 SQLException,可以在抛出时保留原始异常,以便获取数据库返回的具体错误代码和描述。

5、总结 ​

通过在捕获 ActiveRecordException 时主动记录内部 SQL 和参数,不仅能够在不泄露敏感信息的前提下,快速定位数据库异常,还能为后续优化和监控提供有力的数据支持。结合统一处理、脱敏、告警等最佳实践,能够大幅提升系统的健壮性与可维护性。