☰
Spring PlatformTransactionManager 深度解析:Spring 编程式事务的核心入口
2026/10/3 2:22:30 网站建设 项目流程
  • 示例工程
  • 文档

【免费下载链接】spring-reading

涵盖了 Spring 框架的核心概念和关键功能,包括控制反转(IOC)容器的使用,面向切面编程(AOP)的原理与实践,事务管理的方式与实现,Spring MVC 的流程与控制器工作机制,以及 Spring 中数据访问、安全、Boot 自动配置等方面的深入研究。此外,它还包含了 Spring 事件机制的应用、高级主题如缓存抽象和响应式编程,以及对 Spring 源码的编程风格与设计模式的深入探讨。

项目地址:https://gitcode.com/GitHub_Trending/sp/spring-reading
点击查看免费下载

PlatformTransactionManager是 Spring 事务抽象体系中负责管理事务的核心策略接口,为 JDBC、JTA、Hibernate 等不同数据访问技术提供了统一的事务管理入口。本文基于 spring-reading 仓库中 spring-transaction-platformTransactionManager 模块 的文档与源码,系统讲解该接口的四大核心方法、事务传播行为与隔离级别等关键参数、典型编程式事务实战,以及从getTransaction到commit/rollback的完整底层调用链,帮助读者真正吃透 Spring 命令式事务的运作机制。

一、PlatformTransactionManager 是什么

PlatformTransactionManager接口是 Spring 框架中负责管理事务的核心接口,它定义了统一的事务管理方法,包括事务的启动、提交、回滚和获取当前事务状态等。通过这一抽象层,应用程序可以面向统一的事务 API 编程,而无需关心底层具体使用的是 JDBC 连接、JTA 全局事务还是 Hibernate 会话,从而便于在不同数据访问技术之间无缝切换。

它继承自org.springframework.transaction.TransactionManager(Spring 5 中引入的标记接口,同时派生了面向响应式编程的ReactiveTransactionManager),其核心定位是Spring 命令式事务基础架构的中心接口。正如接口源码注释所述:应用可以直接使用它,但更常见的用法是通过TransactionTemplate或基于 AOP 的声明式事务(TransactionInterceptor)来界定事务边界。

二、四大核心功能

1. 开始事务(getTransaction)

PlatformTransactionManager允许我们通过getTransaction(TransactionDefinition definition)方法开始一个新的事务,或获取一个已存在的事务。TransactionDefinition对象定义了事务的属性,如传播行为、隔离级别、超时设置和只读标志等。

TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;

2. 提交事务(commit)

如果事务中的所有操作都成功完成,可以通过commit(TransactionStatus status)方法提交事务,使事务中的所有更改永久化。

void commit(TransactionStatus status) throws TransactionException;

3. 回滚事务(rollback)

如果在事务中发生任何异常或错误,可以通过rollback(TransactionStatus status)方法回滚事务,撤销事务中的所有更改,使数据库回到事务开始前的状态。

void rollback(TransactionStatus status) throws TransactionException;

4. 获取事务状态(TransactionStatus)

TransactionStatus对象提供了关于当前事务状态的信息,如是否是新事务、是否已完成、是否已回滚、是否设置了 rollback-only 等。这些信息可以用于在事务处理过程中进行条件逻辑判断,是连接“事务管理器”与“业务代码”的状态载体。

三、接口源码逐方法解读

仓库文档完整收录了PlatformTransactionManager接口源码(可在 README 中查看),下面提炼每个方法的契约要点:

getTransaction 的语义约定:

  • 根据指定的传播行为返回当前活动事务或创建一个新事务;
  • 隔离级别、超时等参数仅在创建新事务时生效,参与已存在事务时会被忽略;
  • 并非所有事务定义设置都被所有事务管理器支持,遇到不支持的设置时,实现应抛出异常;
  • 唯一例外是只读标志:若不支持显式只读模式应忽略它,只读本质上只是对底层优化的一个提示;
  • 可能抛出TransactionException(查找、创建或系统错误)与IllegalTransactionStateException(事务定义与当前状态冲突,例如 mandatory 传播下无现存事务)。

commit 的语义约定:

  • 根据事务状态提交给定事务;若事务已被程序标记为仅回滚(rollback-only),则执行回滚;
  • 若事务不是新事务,则省略提交以正确参与周围的事务;若先前事务被挂起,提交新事务后恢复先前事务;
  • 提交调用完成(无论正常还是抛异常)时,事务必须完全完成和清理,此时不应再期望回滚调用;
  • 可能抛出UnexpectedRollbackException(协调器启动意外回滚)、HeuristicCompletionException(启发式决策失败)、TransactionSystemException(系统错误)、IllegalTransactionStateException(事务已完成)。

rollback 的语义约定:

  • 若事务不是新事务,则仅将其标记为回滚,以正确参与周围事务;
  • 若先前事务被挂起,回滚新事务后恢复先前事务;
  • 重要约定:若 commit 抛出异常,不要调用 rollback——当 commit 返回时事务已完成清理,提交失败后调用 rollback 将导致IllegalTransactionStateException。

四、事务定义 TransactionDefinition:决定事务行为的参数表

getTransaction的参数TransactionDefinition是控制事务行为的核心配置载体,在仓库的 spring-transaction-transactionDefinition 模块 中有完整源码。它定义了四类属性:传播行为、隔离级别、超时时间、只读标志。

1. 传播行为(Propagation Behavior)

常量值语义
PROPAGATION_REQUIRED0支持当前事务;不存在则新建(默认值,通常定义事务同步范围)
PROPAGATION_SUPPORTS1支持当前事务;不存在则以非事务方式执行
PROPAGATION_MANDATORY2支持当前事务;不存在则抛出异常
PROPAGATION_REQUIRES_NEW3新建事务;存在则挂起当前事务
PROPAGATION_NOT_SUPPORTED4不支持事务;总是以非事务方式执行,存在则挂起
PROPAGATION_NEVER5不支持事务;存在则抛出异常
PROPAGATION_NESTED6存在当前事务时执行嵌套事务,否则行为同 REQUIRED

接口默认返回PROPAGATION_REQUIRED。注意:REQUIRES_NEW与NOT_SUPPORTED的事务挂起并非在所有事务管理器上都自动生效(尤其依赖JtaTransactionManager提供javax.transaction.TransactionManager);NESTED默认仅适用于基于 JDBC 3.0 驱动程序的DataSourceTransactionManager(通过保存点实现)。

2. 隔离级别(Isolation Level)

常量值解决/允许的并发问题
ISOLATION_DEFAULT-1使用底层数据存储的默认隔离级别
ISOLATION_READ_UNCOMMITTED1允许脏读、不可重复读和幻读
ISOLATION_READ_COMMITTED2防止脏读;可能发生不可重复读和幻读
ISOLATION_REPEATABLE_READ4防止脏读和不可重复读;可能发生幻读
ISOLATION_SERIALIZABLE8防止脏读、不可重复读和幻读

这些常量与java.sql.Connection上的对应常量取值一致。隔离级别与超时设置仅对新启动的事务(REQUIRED / REQUIRES_NEW / NESTED)生效,若希望在参与隔离级别不同的现存事务时拒绝声明,可将事务管理器的validateExistingTransactions标志置为true。

3. 超时时间(Timeout)

默认TIMEOUT_DEFAULT = -1,表示使用底层事务系统的默认超时(不支持超时则为无)。指定超时时单位为秒,仅在新建事务时应用;不支持超时的事务管理器在给定非默认值时抛出异常。

4. 只读标志(ReadOnly)

默认false。只读标志适用于任何事务上下文,无论是实际资源事务支持,还是在资源级别非事务性操作(如PROPAGATION_SUPPORTS)。它只是对实际事务子系统的优化提示,不一定会导致写访问尝试失败;不理解该提示的事务管理器在要求只读事务时不会抛出异常。

五、主要实现与类关系图

PlatformTransactionManager的策略接口默认实现是JtaTransactionManager与DataSourceTransactionManager,可作为其他事务策略的实现指南。仓库文档重点介绍了DataSourceTransactionManager,即基于 JDBC 的事务管理器。

此外,官方注释明确建议:实现者应从org.springframework.transaction.support.AbstractPlatformTransactionManager抽象类派生,该类预先实现了传播行为处理与事务同步处理,子类只需实现begin、suspend、resume、commit等底层模板方法。完整类关系如下(来源:README):

classDiagram direction BT class AbstractPlatformTransactionManager class DataSourceTransactionManager class InitializingBean { <<Interface>> } class PlatformTransactionManager { <<Interface>> } class ResourceTransactionManager { <<Interface>> } class TransactionManager { <<Interface>> } AbstractPlatformTransactionManager ..> PlatformTransactionManager DataSourceTransactionManager --> AbstractPlatformTransactionManager DataSourceTransactionManager ..> InitializingBean DataSourceTransactionManager ..> ResourceTransactionManager PlatformTransactionManager --> TransactionManager ResourceTransactionManager --> PlatformTransactionManager

其中ResourceTransactionManager扩展自PlatformTransactionManager,额外提供getResourceFactory()以暴露底层资源工厂(DataSource);DataSourceTransactionManager同时实现了InitializingBean,可在容器中完成初始化校验。

六、最佳实践:基于 JDBC 的编程式事务实战

仓库文档给出了一个完整的编程式事务示例,对应的可直接运行源码位于 PlatformTransactionManagerDemo.java。核心思路:配置数据源与DataSourceTransactionManager,借助JdbcTemplate执行 SQL,手动开启、提交、回滚事务。

1. 准备建表 SQL

示例向scores表插入随机分数,并(在完整版 Demo 中)向scores_log表记录日志,两张表的建表语句见 spring-transaction/sql/test.sql:

CREATE TABLE `scores` ( `id` bigint NOT NULL, `score` decimal(5, 2) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = DYNAMIC; CREATE TABLE `scores_log` ( `id` bigint NOT NULL, `score_id` bigint NULL DEFAULT NULL, `create_time` datetime NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = DYNAMIC;

2. 完整示例代码

public class PlatformTransactionManagerDemo { private static PlatformTransactionManager transactionManager; private static JdbcTemplate jdbcTemplate; public static void main(String[] args) throws SQLException { // 数据库连接 URL,格式为 jdbc:数据库驱动名称://主机地址:端口号/数据库名称 String url = "jdbc:mysql://localhost:3306/spring-reading"; // 数据库用户名 String username = "root"; // 数据库密码 String password = "123456"; // 创建 SimpleDriverDataSource 对象,用于管理数据源 SimpleDriverDataSource dataSource = new SimpleDriverDataSource(new Driver(), url, username, password); // 创建 DataSourceTransactionManager 对象,用于管理事务 transactionManager = new DataSourceTransactionManager(dataSource); // 创建 JdbcTemplate 对象,用于执行 SQL 语句 jdbcTemplate = new JdbcTemplate(dataSource); insertScore(); } private static void insertScore() { // 开启一个新的事务,返回事务状态对象(默认传播行为 PROPAGATION_REQUIRED) TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition()); try { long id = System.currentTimeMillis(); int score = new Random().nextInt(100); // 向数据库中插入随机生成的分数 int row = jdbcTemplate.update("insert into scores(id,score) values(?,?)", id, score); // 模拟异常,用于测试事务回滚 // int i = 1 / 0; // 提交事务 transactionManager.commit(transactionStatus); // 打印影响行数 System.out.println("scores row = " + row); } catch (Exception e) { // 出现异常时回滚事务 transactionManager.rollback(transactionStatus); e.printStackTrace(); } } }

3. 运行要点说明

  • 依赖版本:仓库根 pom.xml 声明 Spring Framework5.2.15.RELEASE、MySQL 驱动8.0.30、Java 11;模块自身的 pom.xml 继承自spring-transaction聚合模块,后者统一引入了mysql-connector-java依赖。
  • 传播行为定制:Demo 源码中实际使用new DefaultTransactionDefinition(DefaultTransactionDefinition.PROPAGATION_REQUIRED)显式指定传播行为;更完整的版本还包含insertScoreLog方法演示多段代码共享同一事务管理器。
  • 回滚验证:将// int i = 1 / 0;取消注释即可模拟运行时异常,观察scores表中不会留下本次插入的数据,验证事务回滚效果。
  • 编程式 vs 声明式:该示例展示的是最底层的编程式事务用法;实际生产环境更推荐通过TransactionTemplate或@Transactional(底层由TransactionInterceptor配合 AOP 实现)来简化事务边界管理。

七、源码级原理分析

本模块文档沿着“开启事务 → 提交事务 → 回滚事务”三条主线,逐层剖析了从PlatformTransactionManager接口到DataSourceTransactionManager具体实现的完整调用链,下面梳理其核心脉络。

1. 开启事务的调用链

(1)入口:AbstractPlatformTransactionManager#getTransaction

该模板方法处理传播行为,委托给doGetTransaction、isExistingTransaction和doBegin。核心逻辑:

  • 未传入定义时使用TransactionDefinition.withDefaults()兜底;
  • 调用doGetTransaction()获取底层事务对象;
  • 通过isExistingTransaction(transaction)判断是否存在活动事务,存在则转交handleExistingTransaction;
  • 新建事务前校验超时:def.getTimeout() < TIMEOUT_DEFAULT时抛出InvalidTimeoutException;
  • 传播行为为PROPAGATION_MANDATORY但无现存事务时,抛出IllegalTransactionStateException;
  • 传播行为为 REQUIRED / REQUIRES_NEW / NESTED 时,先suspend(null)挂起可能存在的资源,再通过startTransaction创建新事务,启动失败则resume(null, suspendedResources)恢复并抛出异常;
  • 其他传播行为(SUPPORTS 等)则返回“空事务”状态——没有实际事务但可能存在同步;若此时指定了自定义隔离级别,仅输出 warn 日志。

(2)获取事务对象:DataSourceTransactionManager#doGetTransaction

创建DataSourceTransactionObject事务对象,设置保存点允许状态(由isNestedTransactionAllowed()决定),并通过TransactionSynchronizationManager.getResource(dataSource)获取当前线程绑定的连接持有者ConnectionHolder,设置到事务对象后返回。

(3)判断现存事务:DataSourceTransactionManager#isExistingTransaction

将事务对象强转为DataSourceTransactionObject,判断其hasConnectionHolder()且getConnectionHolder().isTransactionActive(),即连接持有者中的事务是否处于活动状态。

(4)处理现存事务:AbstractPlatformTransactionManager#handleExistingTransaction

按传播行为分支处理:

  • PROPAGATION_NEVER:存在事务即抛IllegalTransactionStateException;
  • PROPAGATION_NOT_SUPPORTED:suspend(transaction)挂起当前事务,返回无实际事务的新状态;
  • PROPAGATION_REQUIRES_NEW:挂起当前事务后startTransaction新建事务,失败时resumeAfterBeginException恢复;
  • PROPAGATION_NESTED:校验isNestedTransactionAllowed()(否则抛NestedTransactionNotSupportedException);若useSavepointForNestedTransaction()则在现有事务中创建保存点(JDBC 3.0 保存点),否则通过嵌套 begin/commit 创建;
  • 其余(SUPPORTS / REQUIRED):参与现有事务;若启用validateExistingTransaction,还会校验隔离级别与只读标志与现存事务是否兼容,不兼容即抛异常。

(5)启动新事务:AbstractPlatformTransactionManager#startTransaction

决定是否启用事务同步(getTransactionSynchronization() != SYNCHRONIZATION_NEVER),创建DefaultTransactionStatus状态对象,随后调用模板方法doBegin(transaction, definition)真正开启底层事务,最后prepareSynchronization准备事务同步。

(6)JDBC 层开启事务:DataSourceTransactionManager#doBegin

  • 若事务对象没有连接持有者或未与事务同步,则从数据源getConnection()并包装为新的ConnectionHolder;
  • 通过DataSourceUtils.prepareConnectionForTransaction应用隔离级别并记录previousIsolationLevel(提交/回滚后用于还原);
  • 若连接处于自动提交状态,则切换为手动提交并记录mustRestoreAutoCommit;
  • 调用prepareTransactionalConnection后,将连接持有者标记为transactionActive;
  • 根据定义计算超时(determineTimeout)并设置到连接持有者;
  • 若为新的连接持有者,通过TransactionSynchronizationManager.bindResource绑定到当前线程;
  • 任何异常都会释放连接并抛CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex)。

(7)只读强化:DataSourceTransactionManager#prepareTransactionalConnection

当enforceReadOnly标志为true且定义为只读事务时,执行SET TRANSACTION READ ONLY语句(该方法自 Spring 4.3.7 提供,Oracle、MySQL、Postgres 均可理解该语句)。

2. 提交事务的调用链

(1)入口:AbstractPlatformTransactionManager#commit

  • 若status.isCompleted(),抛IllegalTransactionStateException(同一事务不可重复提交/回滚);
  • 若isLocalRollbackOnly()(事务代码请求了回滚),则processRollback(defStatus, false);
  • 若!shouldCommitOnGlobalRollbackOnly()且isGlobalRollbackOnly()(全局标记仅回滚却请求提交),则processRollback(defStatus, true);
  • 否则进入processCommit(defStatus)。

(2)提交处理:AbstractPlatformTransactionManager#processCommit

按序执行:prepareForCommit→triggerBeforeCommit→triggerBeforeCompletion;随后分支处理:

  • 存在保存点(嵌套事务):status.releaseHeldSavepoint()释放保存点;
  • 新事务:调用doCommit(status)真正提交;
  • 若检测到全局回滚标记且出现意外回滚,抛UnexpectedRollbackException("Transaction silently rolled back because it has been marked as rollback-only");
  • 提交异常时:若isRollbackOnCommitFailure()则执行doRollbackOnCommitException,否则以STATUS_UNKNOWN触发 afterCompletion;
  • 成功路径最终触发triggerAfterCommit(此处的异常会传播给调用者,但事务仍视为已提交)与triggerAfterCompletion(STATUS_COMMITTED);
  • 无论成败,finally中执行cleanupAfterCompletion清理。

(3)JDBC 层提交:DataSourceTransactionManager#doCommit

从状态对象中取出DataSourceTransactionObject,再获取Connection,执行con.commit();发生SQLException时通过translateException("JDBC commit", ex)转换为 Spring 事务异常抛出。

3. 回滚事务的调用链

(1)入口:AbstractPlatformTransactionManager#rollback

同样先校验status.isCompleted()(已完成则抛异常),随后将状态强转为DefaultTransactionStatus并委托processRollback(defStatus, false)。

(2)回滚处理:AbstractPlatformTransactionManager#processRollback

  • 先触发triggerBeforeCompletion;
  • 有保存点则rollbackToHeldSavepoint()回滚到保存点(嵌套事务局部回滚);
  • 是新事务则调用doRollback(status)执行真实回滚;
  • 参与较大事务时:若本地回滚或isGlobalRollbackOnParticipationFailure(),则doSetRollbackOnly(status)将现存事务标记为仅回滚;否则交由事务发起方决定;
  • 完成后触发triggerAfterCompletion(STATUS_ROLLED_BACK);若存在全局回滚标记且unexpectedRollback为真,抛UnexpectedRollbackException;
  • finally中执行cleanupAfterCompletion。

(3)JDBC 层回滚:DataSourceTransactionManager#doRollback

获取Connection后执行con.rollback(),SQLException同样通过translateException("JDBC rollback", ex)转换抛出。

八、总结

PlatformTransactionManager是 Spring 命令式事务体系的策略核心:getTransaction负责根据传播行为获取或创建事务,commit/rollback负责最终提交与回滚,TransactionStatus则贯穿始终承载事务状态。理解它,就能从底层看懂@Transactional注解、TransactionTemplate与TransactionInterceptor的运作本质;而AbstractPlatformTransactionManager的模板方法设计(doGetTransaction/doBegin/doCommit/doRollback)也为我们扩展自定义事务管理器提供了清晰的骨架。本模块的 完整源码分析 与 可运行示例 值得结合 TransactionDefinition 模块 一起研读,从而形成对 Spring 事务抽象完整闭环的认知。

  • 示例工程
  • 文档

【免费下载链接】spring-reading

涵盖了 Spring 框架的核心概念和关键功能,包括控制反转(IOC)容器的使用,面向切面编程(AOP)的原理与实践,事务管理的方式与实现,Spring MVC 的流程与控制器工作机制,以及 Spring 中数据访问、安全、Boot 自动配置等方面的深入研究。此外,它还包含了 Spring 事件机制的应用、高级主题如缓存抽象和响应式编程,以及对 Spring 源码的编程风格与设计模式的深入探讨。

项目地址:https://gitcode.com/GitHub_Trending/sp/spring-reading
点击查看免费下载

相关推荐

上一篇:模型进了 Blender 就变成一团乱麻?用 io_scene_psk_psa 插件一次搞定 PSK/PSA 转换
下一篇:Blender 导入虚幻引擎 PSK/PSA 文件终极教程:用 io_scene_psk_psa 插件一次搞定模型与动画

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询