编程式事务异常捕获漏掉会导致事务未提交或回滚,引发数据不一致等问题;必须在finally中重置setautocommit(true),分层捕获sqlexception、runtimeexception、exception,外部调用需包裹异常,资源用try-with-resources确保关闭。

编程式事务中异常捕获漏掉,本质是手动控制事务生命周期时,没覆盖所有异常路径,导致事务既没提交也没回滚,连接挂起、数据不一致、资源泄漏等问题随之而来。
手动开启事务后必须确保 finally 中恢复自动提交
使用 connection.setAutoCommit(false) 后,若未在 finally 块中调用 setAutoCommit(true),连接可能被归还连接池但仍处于手动提交状态。下一次复用该连接的业务会意外继承这个状态,造成“事务静默失效”。
- 务必在
finally中重置自动提交,哪怕前面已调用commit()或rollback() - 不要只依赖
catch块做回滚——finally是兜底保障 - 示例关键结构:
conn.setAutoCommit(false);
// 执行多条SQL
conn.commit();
} catch (SQLException e) {
conn.rollback();
throw e;
} finally {
if (conn != null) conn.setAutoCommit(true); // 关键!
}
异常类型判断不能只靠 try-catch 表层捕获
编程式事务不依赖 Spring AOP,所以没有 @Transactional(rollbackFor = ...) 的自动适配。开发者需自行判断哪些异常该回滚——但容易忽略:同一种业务失败可能抛出多种底层异常(如 SQLTimeoutException、SQLIntegrityConstraintViolationException、IOException),若只捕获 SQLException,其他异常会直接穿透,事务就漏掉了。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 建议按实际风险等级分层捕获:先捕
SQLException,再捕RuntimeException,最后兜底Exception - 避免空
catch或仅打印日志却不回滚 - 对非数据库异常(如网络超时、NPE)也要评估是否应中断并回滚当前事务
嵌套操作或回调中异常容易逃逸
当在事务块内调用外部服务、触发事件监听器、或执行 Lambda 回调时,这些代码抛出的异常若未显式捕获,会直接跳出当前 try 块,导致回滚逻辑不执行。
- 所有事务内调用的外部逻辑,都应视为“潜在异常源”,需包裹或声明处理
- 例如:在
conn操作后调用notifyOrderSuccess(),该方法若抛RemoteException,而你只捕了SQLException,事务就无法回滚 - 更稳妥做法:将事务边界收窄,只包纯粹 DB 操作;非 DB 逻辑移至事务外,用最终一致性补偿
资源未关闭导致事务状态残留
PreparedStatement、ResultSet 异常未处理,可能使语句执行中途失败,但连接仍开着。此时若跳过回滚,后续 commit() 可能因资源状态异常而失败,形成“半提交”假象。
- 使用 try-with-resources 确保语句和结果集自动关闭
- 关闭资源的异常(如
SQLException在close()时抛出)也应记录,但不应掩盖主事务的回滚动作 - 推荐结构:外层 try 控制事务,内层 try-with-resources 控制资源
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










