数据库事务中必须用try-catch-finally确保原子性与资源不泄露:事务开启和commit/rollback须在try及catch/finally中严格控制;catch必须显式rollback并校验连接有效性;finally仅释放资源且按反序close;优先使用try-with-resources自动管理Statement和ResultSet。

数据库事务中用 try-catch-finally,核心目标就一个:保证事务原子性 + 资源不泄露。不是简单“捕获异常就行”,而是要让 commit/rollback 逻辑可控、连接必须释放、业务状态不残留。
事务边界必须由 try 控制
事务开启(如 Connection.setAutoCommit(false))和提交/回滚操作,必须严格落在 try 块内起始处和 catch/finally 的明确分支中。不能把 connection 获取放在 try 外,也不能把 commit 写在 try 结尾却不处理 rollback。
- ✅ 正确做法:事务开启 → 执行 SQL → 成功则 commit → 异常则 rollback
- ❌ 危险写法:try 里只执行 update,commit 放在 try 外 —— 一旦异常抛出,commit 就跳过,事务悬停,连接可能被占用甚至死锁
catch 中必须显式 rollback
数据库事务不会因 Java 异常自动回滚。catch 块不只是记录日志或打印错误,关键要调用 connection.rollback(),否则已执行的 DML 会滞留在事务中,后续可能被意外提交或造成数据不一致。
- rollback 前检查 connection 是否有效(非 null 且未关闭)
- rollback 本身也可能抛 SQLException,建议单独 try 包裹并记录 —— 但绝不吞掉它,至少打 ERROR 日志
- 不要在 catch 里重新 throw 新异常后忽略 rollback,那等于放弃事务控制权
finally 中只做资源释放,不做业务决策
finally 是释放 Connection、PreparedStatement、ResultSet 的唯一可靠位置。它不参与事务成败判断,也不该调用 commit 或 rollback —— 那些必须在 try/catch 分支里完成。
立即学习“Java免费学习笔记(深入)”;
- 按 close 顺序反向操作:ResultSet → PreparedStatement → Connection
- 每个 close 都要判空 + 单独 try-catch,避免一个 close 失败导致后续资源泄漏
- 别在 finally 里写 return 或 throw —— 会覆盖 try/catch 中的返回值或异常,掩盖真实问题
优先用 try-with-resources 替代手写 finally
如果使用 PreparedStatement 或 ResultSet(它们都实现 AutoCloseable),直接用 try-with-resources 可自动关闭,大幅降低 finally 冗余代码和遗漏风险。
- Connection 本身不自动 close,仍需手动管理;但 Statement 和 ResultSet 可放心交给 try-with-resources
- 示例:try (PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery()) { ... } —— rs 和 ps 会在块结束时自动 close,无论是否异常
- 注意:try-with-resources 的隐式 close 也抛异常,若与业务异常并发,后者会被压制(suppressed),需通过 Throwable.getSuppressed() 查看


















