- 示例工程
- 文档
【免费下载链接】spring-reading
涵盖了 Spring 框架的核心概念和关键功能,包括控制反转(IOC)容器的使用,面向切面编程(AOP)的原理与实践,事务管理的方式与实现,Spring MVC 的流程与控制器工作机制,以及 Spring 中数据访问、安全、Boot 自动配置等方面的深入研究。此外,它还包含了 Spring 事件机制的应用、高级主题如缓存抽象和响应式编程,以及对 Spring 源码的编程风格与设计模式的深入探讨。
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_REQUIRED | 0 | 支持当前事务;不存在则新建(默认值,通常定义事务同步范围) |
PROPAGATION_SUPPORTS | 1 | 支持当前事务;不存在则以非事务方式执行 |
PROPAGATION_MANDATORY | 2 | 支持当前事务;不存在则抛出异常 |
PROPAGATION_REQUIRES_NEW | 3 | 新建事务;存在则挂起当前事务 |
PROPAGATION_NOT_SUPPORTED | 4 | 不支持事务;总是以非事务方式执行,存在则挂起 |
PROPAGATION_NEVER | 5 | 不支持事务;存在则抛出异常 |
PROPAGATION_NESTED | 6 | 存在当前事务时执行嵌套事务,否则行为同 REQUIRED |
接口默认返回PROPAGATION_REQUIRED。注意:REQUIRES_NEW与NOT_SUPPORTED的事务挂起并非在所有事务管理器上都自动生效(尤其依赖JtaTransactionManager提供javax.transaction.TransactionManager);NESTED默认仅适用于基于 JDBC 3.0 驱动程序的DataSourceTransactionManager(通过保存点实现)。
2. 隔离级别(Isolation Level)
| 常量 | 值 | 解决/允许的并发问题 |
|---|---|---|
ISOLATION_DEFAULT | -1 | 使用底层数据存储的默认隔离级别 |
ISOLATION_READ_UNCOMMITTED | 1 | 允许脏读、不可重复读和幻读 |
ISOLATION_READ_COMMITTED | 2 | 防止脏读;可能发生不可重复读和幻读 |
ISOLATION_REPEATABLE_READ | 4 | 防止脏读和不可重复读;可能发生幻读 |
ISOLATION_SERIALIZABLE | 8 | 防止脏读、不可重复读和幻读 |
这些常量与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 Framework
5.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 源码的编程风格与设计模式的深入探讨。
相关推荐
【免费下载】 深入理解Spring事务管理:PlatformTransactionManager核心解析
深入理解Spring事务管理:PlatformTransactionManager核心解析 概述 在Spring框架中,事务管理是一个至关重要的功能模块。 Pl
示例工程文档Spring与事务处理:声明式事务设计与PlatformTransactionManager源码深度解析
Spring与事务处理:声明式事务设计与PlatformTransactionManager源码深度解析 JavaEE 应用中的事务处理是一个重要且涉及范围很广
文档教程知识库Spring Framework 编程式事务管理深度解析
Spring Framework 编程式事务管理深度解析 引言:为什么需要编程式事务管理? 在企业级应用开发中,事务管理是确保数据一致性和完整性的核心技术。虽然
后端Web框架依赖注入
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考