bigywater.tech
Spring · 35

TransactionTemplate 与编程式事务

什么时候该用编程式事务?TransactionTemplate 和 @Transactional 有什么不同?事务超时是怎么实现的?事务范围放得太宽会怎样?这篇在 Spring Framework 7.0.9、HikariCP 和 MySQL 26.7.0 上逐项量出来。

1225 → 308 ms
把 300 ms 的非数据库工作移出事务后,8 个线程共用 2 个连接时全部完成的时间
1025 ms
setTimeout(1) 的事务里 select sleep(3) 被取消的用时
0 行
同类里 this 调用时 TransactionTemplate 仍然回滚(@Transactional 则剩 1 行)

基本用法

实测 · 本机执行输出
  execute 返回值                              → 正常返回 返回值                                             表里剩 1 行 → 提交
  回调里抛 RuntimeException                    → IllegalStateException                                表里剩 0 行 → 回滚
  回调里 status.setRollbackOnly()             → 正常返回                                                 表里剩 0 行 → 回滚
  受检异常包成 RuntimeException                  → RuntimeException ← IOException                       表里剩 0 行 → 回滚

execute 返回回调的值,抛运行时异常或 setRollbackOnly() 都回滚。

没有自调用问题

实测 · 本机执行输出
  @Transactional 方法被同类方法 this 调用           → IllegalStateException                                表里剩 1 行 → 提交
  TransactionTemplate 在同类方法里使用             → IllegalStateException                                表里剩 0 行 → 回滚

TransactionTemplate 直接调事务管理器,不依赖代理。

属性

实测 · 本机执行输出
  事务内:隔离级别=8(8 = SERIALIZABLE),只读=true
  setTimeout(1) 的事务里执行 select sleep(3):QueryTimeoutException ← MySQLTimeoutException: Statement cancelled due to timeout or client request(用时 1025 ms)

隔离级别、只读、超时都可以在模板上设置,超时靠语句超时实现。

缩小事务范围

实测 · 本机执行输出
    @Transactional 包住整个方法(300 ms 的非数据库工作在事务里):8 个线程并发,连接池只有 2 个连接 → 全部完成用了 1225 ms
    TransactionTemplate 只包数据库那一步(300 ms 的非数据库工作在事务外):8 个线程并发,连接池只有 2 个连接 → 全部完成用了 308 ms

只把数据库操作放进事务,连接占用时间短,连接池吞吐高得多。

分步演示

编程式事务
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动。用不带 Boot 的 Spring Framework 7.0.9 + DataSourceTransactionManager + HikariCP(第四节连接池大小 2)+ 自己起的 MySQL 26.7.0;300 ms 的非数据库工作用 Thread.sleep 模拟;总耗时每次运行有十几 ms 的抖动
    • 没有验证:TransactionTemplate 在响应式环境里的替代(TransactionalOperator);嵌套 TransactionTemplate 与传播行为组合;事务超时在不同数据库驱动上的实现差别(只测了 MySQL Connector/J);PlatformTransactionManager 手工 getTransaction / commit / rollback 的泄漏风险
    京ICP备2026067502号-1京公网安备11010502063487号