异常处理
ActiveRecordException
1、背景简介
在使用 Java-DB(即 LitongJava ActiveRecord 框架)操作数据库时,当执行增删改查操作失败,框架会抛出 ActiveRecordException
。出于安全考虑,该异常默认不会将完整的 SQL 语句及参数打印到控制台,而是将它们保存在异常对象内部,避免敏感信息泄露。
2、异常捕获与日志记录
为了既能保证安全性,又能方便排查问题,需要在捕获 ActiveRecordException
时,主动将其内部保存的 SQL 语句和参数输出到日志。示例代码如下:
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:
com.litongjava.db.activerecord.ActiveRecordException: ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification
at com.litongjava.db.activerecord.DbPro.update(DbPro.java:443)
at com.litongjava.db.activerecord.DbPro.update(DbPro.java:477)
at com.litongjava.db.activerecord.Db.updateBySql(Db.java:207)
at com.tio.mail.wing.service.MailboxService.storeFlags(MailboxService.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)
…
通过上述日志,我们能够清晰地看到:
- 出错位置:
line=14
。 - 执行的 SQL:完整的
INSERT INTO ...
语句。 - 绑定参数:三个具体值
[528755689311666176, 528442583916969984, \Seen]
。 - 异常堆栈:快速定位到底是哪个方法、哪一行代码引发的问题。
4、最佳实践建议
统一异常处理
- 将上述捕获逻辑封装到一个公共工具或基类中,所有 DAO/Service 层操作均可复用,避免重复代码。
- 可针对不同业务场景,进一步细化日志级别(
ERROR
、WARN
)及格式。
敏感信息屏蔽
- 在生产环境中,若 SQL 或参数中可能包含敏感数据(如密码、用户隐私),应对敏感字段做过滤或脱敏后再记录。
告警与监控
- 对频繁抛出
ActiveRecordException
的场景设置告警,及时发现和修复数据库性能或语法问题。 - 将关键异常推送至监控平台(如 Sentry、Prometheus + Alertmanager)以便实时跟踪。
- 对频繁抛出
异常链处理
- 如果
ActiveRecordException
的根因是底层SQLException
,可以在抛出时保留原始异常,以便获取数据库返回的具体错误代码和描述。
- 如果
5、总结
通过在捕获 ActiveRecordException
时主动记录内部 SQL 和参数,不仅能够在不泄露敏感信息的前提下,快速定位数据库异常,还能为后续优化和监控提供有力的数据支持。结合统一处理、脱敏、告警等最佳实践,能够大幅提升系统的健壮性与可维护性。