java异常处理与事务回滚需确保异常触达事务机制:运行时异常默认回滚,检查异常须显式配置rollbackfor;手动事务中必须在catch块显式调用rollback;资源释放须用try-with-resources+finally双保险,按resultset→statement→connection反序关闭。

Java 异常处理与事务回滚要正确配合,核心是让异常真正“触达”事务管理机制,并确保回滚动作及时、准确、不遗漏资源。不是只要 catch 住异常就安全了,关键在于异常是否被事务框架感知、是否触发 rollback、连接和语句是否彻底释放。
运行时异常默认回滚,检查异常需显式声明
Spring 的 @Transactional 默认只对 RuntimeException 及其子类(如 IllegalArgumentException、NullPointerException)和 Error 自动回滚。这是设计使然,不是疏漏。
- 业务校验失败直接 throw new IllegalArgumentException("金额不能为负") → 自动回滚
- 调用外部服务抛出 IOException → 默认不回滚,必须加 @Transactional(rollbackFor = IOException.class)
- 想统一覆盖所有异常?可写 rollbackFor = Exception.class,但要注意 noRollbackFor 优先级更高,且异常必须抛出到代理方法边界(不能在方法内 try-catch 吞掉)
手动事务中,rollback 必须在 catch 块里显式调用
JDBC 层没有“自动回滚”概念。即使发生 SQLException,Connection 也不会自己 rollback——必须人工干预。
- 开启事务:conn.setAutoCommit(false) 必须在 try 块开头
- 成功路径:执行完所有 SQL 后,conn.commit()
- 异常路径:catch 中先 conn.rollback(),再记录日志或包装重抛;rollback 调用本身也可能抛 SQLException,要单独捕获处理
- 别把 commit 放在 try 外面——一旦异常跳出,commit 就跳过,事务悬停,连接可能被长期占用
资源释放必须严格,推荐 try-with-resources + finally 双保险
Statement、ResultSet、Connection 都是稀缺资源,泄漏会快速拖垮数据库连接池。
- PreparedStatement 和 ResultSet 优先用 try-with-resources 自动关闭
- Connection 仍建议放在 finally 块中 close(或恢复 auto-commit),并按反序释放:ResultSet → Statement → Connection
- 不要在 finally 里无条件 conn.close() —— 如果 conn 是从连接池获取的,close 实际是归还,但若之前 rollback 失败导致连接异常,close 可能再次报错;应先判空再 try-close
避免常见陷阱:吞异常、跨连接、假事务
很多“看似回滚了,数据却没还原”的问题,根源不在异常类型,而在执行环境错位。
- 在事务方法内部用 try-catch 把异常吃掉,又不重新 throw → Spring 完全感知不到异常,必然不回滚
- 读写分离场景下,update 走主库,紧接着 select 路由到从库 → 查不到刚改的值,误以为没生效;应强制 Db::master()->... 或统一用写库连接查询
- 嵌套调用多个 @Transactional 方法,默认 propagation=REQUIRED 是加入同一事务,但若中间方法自己 catch 并吞异常,外层无法回滚;需要传播行为对齐或改用 REQUIRES_NEW 明确隔离
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











