关闭自动提交仅禁用自动提交机制,事务实际始于首条dml执行;必须显式commit()生效,否则连接关闭时静默回滚;rollback()仅对未提交更改有效且不可部分回滚,需用savepoint实现局部回滚;连接池中需每次获取后重置autocommit状态。

关键在于关闭自动提交后,用同一连接执行全部操作,并在逻辑终点统一 commit 或 rollback —— AutoCommit 不是开关,而是事务行为的底层约束。
关闭 AutoCommit 是前提,但不是事务起点
调用 setAutoCommit(false) 只是禁用自动提交机制,数据库并不会立刻开启事务。真正触发事务上下文的是第一条 DML(INSERT/UPDATE/DELETE)语句执行那一刻。多表操作中,只要所有 SQL 都走同一个 Connection,且未 commit,它们天然属于同一事务边界。
- 务必在获取连接后第一时间设置
connection.setAutoCommit(false) - 避免在中间穿插 SELECT(它不参与事务,但可能影响业务判断)
- 若使用连接池(如 HikariCP),每次从池中取出连接都需重置 autoCommit 状态,否则可能继承上一个会话残留的 false 值,引发意外长事务
多物理表操作必须共用一个 Connection
跨表更新(比如订单表 + 库存表 + 日志表)若分散在不同 Connection 上,即使都设了 setAutoCommit(false),也无法保证原子性——每个连接各自为政,rollback 只作用于本连接内的更改。
- Spring 中应使用
@Transactional注解或TransactionTemplate,确保整个方法内复用同一 DataSource 获取的 Connection - 原生 JDBC 需手动传递 connection 对象,不能每个 DAO 自己 new Connection
- 注意:DataSource.getConnection() 在事务上下文中通常返回代理连接,实际仍是同一个物理连接
回滚只能全量,局部回滚需靠 Savepoint
标准 rollback() 会撤销自上次 commit 或 rollback 以来的所有变更,无法只撤某张表的操作。若要在多表流程中支持“某一步失败,仅回退该步”,必须插入保存点(Savepoint)。
- 执行
Savepoint sp1 = connection.setSavepoint("sp1")标记位置 - 后续出错时调用
connection.rollback(sp1),只回退到该点,保留之前操作 - MySQL 5.6+、PostgreSQL、Oracle 均支持;但注意 Savepoint 不能跨连接,也不能在 autocommit=true 下生效
- 示例:先写订单主表 → 设 savepoint → 再扣库存 → 若失败则 rollback to savepoint,订单仍可保留(需业务层决定是否允许)
异常路径必须显式 rollback,不能依赖 finally
try-catch-finally 结构中,rollback 必须放在 catch 块里,而非 finally。否则成功时也会误 rollback,导致数据丢失。
- commit 和 rollback 都不可无条件执行;应只在业务逻辑确认成功后 commit,在捕获 SQLException 或业务异常时 rollback
- 连接关闭前未 commit,MySQL 默认静默回滚(尤其 autocommit=false 且未显式操作时)
- 建议在 catch 中打印日志并抛出封装异常,避免吞掉错误掩盖问题











