需要setautocommit(false)是因为默认自动提交模式下每条sql立即生效且不可回滚,无法保证多语句原子性;设为false后sql暂存事务中,需显式commit或rollback。

在 Java 中使用 JDBC 手动控制事务,核心就是调用 Connection.setAutoCommit(false) 关闭自动提交,再配合 commit() 和 rollback() 显式管理事务边界。
为什么需要 setAutoCommit(false)
默认情况下,JDBC 连接处于自动提交模式(autoCommit = true),每条 SQL 执行后立即生效、不可回滚。这无法满足“多条语句要么全成功、要么全失败”的业务需求(比如转账:扣款 + 入账必须原子执行)。调用 setAutoCommit(false) 后,所有后续 SQL 都会暂存在当前事务中,直到主动 commit() 才真正写入数据库,或 rollback() 撤销全部操作。
基本使用步骤
手动事务控制需严格遵循以下顺序:
- 从数据源获取
Connection,立即调用conn.setAutoCommit(false) - 执行一组相关 SQL(如
PreparedStatement.executeUpdate()) - 若全部成功,调用
conn.commit() - 若发生异常,必须捕获并调用
conn.rollback() - 无论成功失败,最后都要在
finally块中恢复autoCommit状态(可选但推荐)并关闭连接
关键注意事项
实际使用中容易出错的点:
- 异常必须捕获并 rollback:未 catch 异常会导致事务挂起,连接可能被占用甚至引发数据库锁
- 不要在事务中混用多个 Connection:每个 Connection 是独立事务上下文,跨连接的 SQL 无法构成一个原子事务
- setAutoCommit(false) 的作用范围是当前 Connection:它不影响其他线程或连接,也不持久化到连接池下次复用(连接池通常会在归还时重置为 autoCommit=true)
- 避免长时间事务:持有事务过久会阻塞其他操作,尤其在高并发场景下易引发死锁或超时
简单代码示例
以转账为例(省略资源关闭细节,实际应使用 try-with-resources):
Connection conn = dataSource.getConnection();
try {
conn.setAutoCommit(false); // 关键:关闭自动提交
<pre class="brush:java;toolbar:false;">PreparedStatement ps1 = conn.prepareStatement("UPDATE account SET balance = balance - ? WHERE id = ?");
ps1.setDouble(1, 100.0);
ps1.setInt(2, 1001);
ps1.executeUpdate();
PreparedStatement ps2 = conn.prepareStatement("UPDATE account SET balance = balance + ? WHERE id = ?");
ps2.setDouble(1, 100.0);
ps2.setInt(2, 1002);
ps2.executeUpdate();
conn.commit(); // 全部成功,提交事务} catch (SQLException e) { conn.rollback(); // 出错则回滚 throw e; } finally { conn.setAutoCommit(true); // 恢复默认状态(连接池友好) conn.close(); }
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











