编程式事务手动控制的核心是绕过spring自动代理,直接操作connection或transactionstatus显式提交/回滚;关键在于复用同一connection、正确管理autocommit状态,并在finally中恢复与释放资源。

在编程式事务中手动控制提交与回滚边界,核心是绕过 Spring 的自动事务代理机制,直接操作底层事务资源(如 Connection 或 TransactionStatus),由开发者显式决定何时 commit 或 rollback。
基于原生 JDBC 手动控制事务边界
适用于对事务粒度要求极高、需跨多个数据源或规避 Spring AOP 限制的场景。关键在于获取并管理同一个 Connection 实例:
- 调用
connection.setAutoCommit(false)关闭自动提交,开启事务上下文 - 所有 SQL 操作必须复用该 connection(不能通过新获取的 connection 执行)
- 业务逻辑执行完毕后,显式调用
connection.commit()或connection.rollback() - 务必在
finally块中恢复setAutoCommit(true)并关闭连接,避免连接泄漏
使用 TransactionTemplate 配合回调外的异常捕获
TransactionTemplate 默认自动提交/回滚,但可通过封装逻辑实现“手动感”控制:
- 在回调函数(
doInTransaction)内不抛出异常,而是用返回值或状态对象标记执行结果 - 回调外根据业务判断是否需要额外补偿或人工干预,再决定是否触发回滚(实际仍靠异常驱动)
- 若真需跳出模板约束,可注入
PlatformTransactionManager,调用getTransaction()获取TransactionStatus,再调用status.setRollbackOnly()主动标记回滚
直接使用 PlatformTransactionManager 编程式控制
这是最接近“纯手动”的方式,完全脱离注解和模板封装:
- 注入
PlatformTransactionManager,调用transactionManager.getTransaction(def)显式开启事务,获得TransactionStatus - 在 try 块中执行业务逻辑,成功则调用
transactionManager.commit(status) - 在 catch 块中调用
transactionManager.rollback(status) - 注意:同一事务内不可重复 commit/rollback;status 对象不可跨线程共享
注意事项与常见陷阱
手动事务边界容易出错,需特别关注:
- Connection 必须来自同一 DataSource 且未被 Spring 事务管理器代理包裹(否则 setAutoCommit 可能失效)
- Spring 管理的 JdbcTemplate 或 MyBatis SqlSession 若已绑定事务上下文,直接操作原始 Connection 可能引发冲突
- 手动事务不参与 Spring 的事务传播(如 REQUIRES_NEW),嵌套调用时需自行隔离
- 务必保证 rollback 和 commit 只执行一次,重复调用会抛出
IllegalTransactionStateException
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











