异常捕获后必须重建一致性边界,明确数据责任归属,通过rollback清理内存状态、触发补偿动作、重置业务字段,并在finally中校验与修复不一致,结合幂等补偿链路保障最终一致。

异常捕获后若不主动干预,状态和数据很容易“脱节”——比如数据库已更新但缓存没刷新,或事务已回滚但内存计数器仍递增。关键不是“有没有捕获”,而是“捕获之后是否重建了一致性边界”。
明确异常后的数据责任归属
一旦 catch 到异常,当前操作的原子性已被打破,必须立刻判断:哪些资源已变更?哪些尚未生效?哪些处于中间态?
- 本地事务中,rollback 后要清空所有关联的内存状态(如临时缓存、统计计数器、待发送消息队列)
- 分布式调用失败时,不能只记录日志,需触发补偿动作(如调用逆向接口、发对账任务、标记待修复)
- 若使用 try-with-resources,资源自动关闭不等于业务状态归位,仍需在 catch 块中重置业务字段(如将订单状态从“处理中”设为“异常”)
避免“静默恢复”导致隐性不一致
常见错误是捕获异常后仅打印日志或返回默认值,而共享变量、缓存、下游服务状态未同步修正。
- 例如:更新用户积分时 DB 执行成功但 Redis 缓存更新抛出 IOException,若 catch 后不做任何处理,后续读取将返回旧值
- 解决方案:采用“两阶段写”或“缓存延迟双删”,并在 catch 中补发失效指令(如 deleteAsync("user:1001"))
- 对非幂等操作,捕获异常后应拒绝静默忽略,转为明确抛出自定义业务异常(如 InsufficientBalanceException),由上层决定重试或降级
利用 finally 统一收口状态
finally 不是“善后兜底”,而是强制执行一致性校验与清理的唯一可靠位置。
- 在 finally 中检查关键状态:DB 记录是否存在、缓存是否命中、MQ 是否已投递
- 若发现不一致(如 DB 写入成功但 MQ 发送失败),可启动异步修复线程或落库待调度任务
- 注意:不要在 finally 中 throw 新异常,否则会掩盖原始异常;可用日志+告警代替
结合补偿机制构建闭环
单次异常捕获无法保证最终一致,需设计可追踪、可重试、可对账的补偿链路。
- 记录操作上下文(traceId、业务单号、前后状态快照)到独立日志表或消息队列
- 补偿任务需自带幂等键(如 order_id + action_type),支持按时间窗口扫描异常记录
- 对强一致性要求场景,可引入 Saga 模式:每个步骤有正向操作和对应补偿操作,异常时反向执行
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











