受检异常日志应由业务层记录并附带上下文,dao/工具层不应记录;统一转换为非受检异常时需保留原始堆栈并说明意图;日志级别依业务影响而定,非一律error。

Java受检异常本身不决定日志怎么记,关键在于“谁处理它”以及“处理时是否真正响应了问题”。日志记录不是为异常类型服务的,而是为排查服务的——哪怕捕获的是IOException,如果只是包装后抛出,就不该在中间层打日志;如果在业务层做了重试或降级,那就要带上下文记录。
受检异常捕获后必须记录上下文,不能只记类型
受检异常(如SQLException、IOException)往往对应外部依赖失败,单纯记录"SQLException occurred"毫无价值。要明确失败发生在哪一环:
- 记录触发异常的具体操作,比如
"query user profile by userId=876543" - 附带关键参数:数据库连接URL(脱敏后)、SQL语句前50字符、执行耗时
- 若调用第三方服务,记录对方接口地址、请求ID、HTTP状态码(如有)
不要在DAO或工具层记录受检异常日志
受检异常常出现在底层IO或数据访问中,但这些层通常不具备业务语义。例如:
-
JDBCUtils.executeQuery()捕获SQLException后只应抛出,不记日志 -
FileUtils.readFile()里用try-catch IOException并打印堆栈,属于典型错误 - 真正该记录的位置是业务方法——比如“用户导出报表失败”,此时才能关联订单号、用户角色、时间范围等可追溯字段
统一转换时保留原始异常,且日志中体现转换意图
多数Spring项目会把受检异常转为非受检异常(如BusinessException),这是合理做法,但转换过程需留痕:
- 构造新异常时用
new BusinessException("报表生成失败", originalException),确保堆栈完整 - 日志消息中说明转换逻辑,例如
"将SQLException封装为业务异常:DB connection timeout, fallback to cached data" - 避免写
throw new RuntimeException(e)——丢失语义,也绕过全局异常处理器的分类处理能力
受检异常的日志级别要匹配实际影响
不是所有受检异常都该打ERROR。它的严重性取决于业务场景:
-
FileNotFoundException在尝试读取用户上传的附件时发生 →WARN(前端已校验,属偶发缺失) -
SQLException导致支付扣款事务回滚 →ERROR(资金链路中断,需人工介入) -
TimeoutException调用风控接口超时,但已启用本地规则兜底 →WARN,并注明"fallback applied"
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











