掌握 Spring 中编程式事务 的完整使用方法,编程式事务是相对于@Transactional声明式事务的灵活方案,适合需要手动精细控制事务的场景(比如根据自定义业务规则决定回滚、事务内多分支条件控制等)。
Spring 提供了3 种主流的编程式事务实现方式 ,按推荐程度 + 使用简洁度 排序,从最推荐(无侵入、封装性好) 到最底层(灵活性最高) 依次讲解,所有示例均基于 Spring Boot(自动配置事务管理器,无需额外配置),兼顾原理 和可直接运行的实战代码。
前置基础
- Spring Boot 会自动根据数据源创建
DataSourceTransactionManager(事务管理器),无需手动配置 Bean; - 编程式事务的核心是 **
TransactionStatus** 接口:用于标记事务状态(如setRollbackOnly()手动标记回滚),是所有编程式事务的控制入口; - 核心抽象:
PlatformTransactionManager(顶级事务管理器)、TransactionDefinition(事务定义,如传播行为、隔离级别)、TransactionStatus(事务状态),三者关系:事务管理器根据事务定义创建事务,返回事务状态用于控制。
方式一:使用TransactionTemplate(最推荐)
核心特点
- Spring 官方推荐 ,基于模板方法模式封装,无需手动处理事务的开启 / 提交 / 回滚,只需关注业务逻辑;无需手动处理事务生命周期,同时支持自定义事务属性(传播行为、隔离级别等)和有 / 无返回值场景。
- 无侵入:业务类无需继承 / 实现任何 Spring 类,符合依赖注入(DI)思想;
- 封装性好 :自动处理异常回滚,代码简洁,是开发中最常用的编程式事务方案。
核心方法
TransactionTemplate的核心方法execute(TransactionCallback<T>),支持有返回值 和无返回值两种重载:
execute(TransactionCallback<T>):有返回值,适合需要从事务内返回业务数据的场景;executeWithoutResult(Consumer<TransactionStatus>):无返回值,适合纯操作型业务(如插入 / 更新)。
实战示例
- 基础依赖(Spring Boot)
只需引入核心的数据库依赖,Spring Boot 自动配置TransactionTemplate和事务管理器:
XML
<!-- 核心:Spring Boot事务自动配置依赖(spring-boot-starter包含) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- MyBatis/MyBatis-Plus + 数据源 持久层+数据源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.20</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
- 核心 API
TransactionTemplate的核心是两个执行方法 ,覆盖无返回值 和有返回值 所有业务场景,事务控制的核心是TransactionStatus接口(手动标记回滚的入口):
| 方法 | 作用 | 适用场景 |
|---|---|---|
executeWithoutResult(Consumer<TransactionStatus>) |
无返回值执行事务 | 插入 / 更新 / 删除等纯操作型业务(最常用) |
execute(TransactionCallback<T>) |
有返回值执行事务 | 插入后返回主键、查询 + 操作后返回结果等 |
TransactionStatus.setRollbackOnly() |
手动标记事务回滚 | 自定义业务规则回滚(无异常场景的核心) |
- 默认事务属性
TransactionTemplate的默认配置满足绝大多数场景,无需手动修改:
- 传播行为:
PROPAGATION_REQUIRED(有则加入,无则新建); - 隔离级别:
ISOLATION_DEFAULT(跟随数据库默认,MySQL 为可重复读,Oracle 为读已提交); - 超时时间:
-1(永不超时); - 只读属性:
false(支持读写操作)。
二、快速使用(默认事务属性)
这是日常开发中最常用的场景 ,直接注入TransactionTemplate,使用默认配置,重点掌握无返回值 和有返回值 两种写法,以及自定义规则手动回滚的核心操作。
场景 1:无返回值事务(插入 / 更新 / 删除)
适用于订单创建、用户新增、数据删除等无需返回业务数据 的场景,使用executeWithoutResult,核心是通过TransactionStatus.setRollbackOnly()实现无异常手动回滚。
实战代码(模拟创建订单,订单金额为 0 则手动回滚):
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionTemplate;
import java.math.BigDecimal;
@Service
public class OrderService {
// 直接注入Spring自动配置的TransactionTemplate
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private OrderMapper orderMapper; // 持久层Mapper(MyBatis/MyBatis-Plus)
@Autowired
private LogMapper logMapper; // 日志持久层
/**
* 无返回值编程式事务:创建订单(核心实战)
*/
public void createOrder(Order order) {
// 事务模板执行核心方法
transactionTemplate.executeWithoutResult(status -> {
try {
// 1. 执行业务操作(同一会话,共享事务)
orderMapper.insert(order); // 插入订单
// 插入订单日志(若事务回滚,日志也会一起回滚)
Log orderLog = new Log();
orderLog.setOrderId(order.getId());
orderLog.setContent("创建订单:" + order.getOrderNo());
logMapper.insert(orderLog);
// 2. 自定义业务规则:无异常时手动标记回滚(核心)
if (order.getAmount().compareTo(BigDecimal.ZERO) == 0) {
status.setRollbackOnly(); // 标记事务为「仅回滚」
System.out.println("订单金额为0,事务手动标记回滚");
return;
}
// 3. 无异常+无手动回滚 → 事务自动提交
} catch (Exception e) {
// 4. 有异常时:手动标记回滚(也可省略,模板会自动回滚)
status.setRollbackOnly();
throw new RuntimeException("创建订单失败", e); // 抛出异常,上层可捕获
}
});
}
}
场景 2:有返回值事务(插入返回主键 / 查询返回结果)
适用于需要从事务内返回业务数据 的场景,比如插入订单后返回订单 ID、批量操作后返回成功条数、查询 + 修改后返回结果,使用execute(TransactionCallback<T>),泛型指定返回值类型。
实战代码(创建订单后返回订单 ID,回滚时返回标识值):
java
/**
* 有返回值编程式事务:创建订单并返回订单ID
*/
public Long createOrderAndReturnId(Order order) {
// 泛型指定返回值为Long,TransactionCallback封装业务逻辑
return transactionTemplate.execute(status -> {
try {
orderMapper.insert(order);
Log orderLog = new Log();
orderLog.setOrderId(order.getId());
logMapper.insert(orderLog);
// 自定义规则:金额为0则标记回滚,返回-1作为标识
if (order.getAmount().compareTo(BigDecimal.ZERO) == 0) {
status.setRollbackOnly();
return -1L;
}
// 提交事务,返回订单主键ID
return order.getId();
} catch (Exception e) {
status.setRollbackOnly();
throw new RuntimeException("创建订单失败", e);
}
});
}
调用示例:
java
// 调用有返回值方法
Long orderId = orderService.createOrderAndReturnId(order);
if (orderId == -1L) {
System.out.println("订单创建失败,事务已回滚");
} else {
System.out.println("订单创建成功,订单ID:" + orderId);
}
三、自定义事务属性
若默认的事务属性无法满足需求(比如需要独立事务 、指定隔离级别 、设置超时时间 ),可通过两种方式 自定义TransactionTemplate的属性,推荐构造方法手动创建(按需配置,更灵活)。
方式 1:构造方法手动创建(推荐,精准配置)
通过手动new TransactionTemplate(),绑定事务管理器并设置自定义属性,适用于单个业务需要特殊事务配置 的场景,不影响全局TransactionTemplate。
实战代码:
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.TransactionTemplate;
@Service
public class OrderService {
// 注入默认的事务管理器
@Autowired
private DataSourceTransactionManager transactionManager;
// 手动创建TransactionTemplate,自定义事务属性(成员变量,单例)
private final TransactionTemplate customTxTemplate;
// 构造方法注入,初始化自定义事务模板
public OrderService() {
this.customTxTemplate = new TransactionTemplate();
// 1. 绑定事务管理器(必须)
this.customTxTemplate.setTransactionManager(transactionManager);
// 2. 自定义传播行为:新建独立事务(主事务回滚不影响此事务)
this.customTxTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
// 3. 自定义隔离级别:读已提交(解决脏读)
this.customTxTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
// 4. 设置事务超时时间:3秒(超过则强制回滚)
this.customTxTemplate.setTimeout(3);
// 5. 只读事务(仅查询用,写操作设置会报错)
// this.customTxTemplate.setReadOnly(true);
}
// 业务方法:使用自定义事务模板
public void createOrderWithCustomTx(Order order) {
customTxTemplate.executeWithoutResult(status -> {
// 业务逻辑和之前一致
orderMapper.insert(order);
// ... 自定义回滚规则
});
}
}
方式 2:全局配置(修改默认 TransactionTemplate)
通过@Bean重新定义TransactionTemplate,覆盖 Spring Boot 的自动配置,适用于项目所有业务需要统一事务属性的场景。
配置类代码:
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;
@Configuration
public class TransactionConfig {
// 重新定义TransactionTemplate,全局生效
@Bean
public TransactionTemplate transactionTemplate(DataSourceTransactionManager transactionManager) {
TransactionTemplate txTemplate = new TransactionTemplate();
txTemplate.setTransactionManager(transactionManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
txTemplate.setTimeout(5);
return txTemplate;
}
}
四、高级场景:多数据源下的 TransactionTemplate 使用
多数据源场景下,核心是为每个数据源创建独立的事务管理器 ,并绑定对应的TransactionTemplate,实现不同数据源的事务隔离。
步骤 1:配置多数据源和对应事务管理器
java
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;
import javax.sql.DataSource;
@Configuration
public class MultiDatasourceConfig {
// 数据源1:主库(mysql1)
@Primary
@Bean("mysql1DataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.mysql1")
public DataSource mysql1DataSource() {
return DruidDataSourceBuilder.create().build();
}
// 数据源2:从库/业务库(mysql2)
@Bean("mysql2DataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.mysql2")
public DataSource mysql2DataSource() {
return DruidDataSourceBuilder.create().build();
}
// 事务管理器1:绑定主库数据源
@Primary
@Bean("mysql1TxManager")
public DataSourceTransactionManager mysql1TxManager(@Autowired DataSource mysql1DataSource) {
return new DataSourceTransactionManager(mysql1DataSource);
}
// 事务管理器2:绑定业务库数据源
@Bean("mysql2TxManager")
public DataSourceTransactionManager mysql2TxManager(@Autowired DataSource mysql2DataSource) {
return new DataSourceTransactionManager(mysql2DataSource);
}
// TransactionTemplate1:绑定主库事务管理器
@Primary
@Bean("mysql1TxTemplate")
public TransactionTemplate mysql1TxTemplate(@Autowired DataSourceTransactionManager mysql1TxManager) {
return new TransactionTemplate(mysql1TxManager);
}
// TransactionTemplate2:绑定业务库事务管理器
@Bean("mysql2TxTemplate")
public TransactionTemplate mysql2TxTemplate(@Autowired DataSourceTransactionManager mysql2TxManager) {
return new TransactionTemplate(mysql2TxManager);
}
}
步骤 2:业务层注入指定的 TransactionTemplate
java
@Service
public class MultiDatasourceService {
// 注入主库的TransactionTemplate
@Autowired
@Qualifier("mysql1TxTemplate")
private TransactionTemplate mysql1TxTemplate;
// 注入业务库的TransactionTemplate
@Autowired
@Qualifier("mysql2TxTemplate")
private TransactionTemplate mysql2TxTemplate;
@Autowired
private OrderMapper orderMapper; // 主库Mapper
@Autowired
private UserMapper userMapper; // 业务库Mapper
// 操作主库的事务方法
public void operateMysql1(Order order) {
mysql1TxTemplate.executeWithoutResult(status -> {
orderMapper.insert(order);
// ... 业务逻辑
});
}
// 操作业务库的事务方法
public void operateMysql2(User user) {
mysql2TxTemplate.executeWithoutResult(status -> {
userMapper.insert(user);
// ... 业务逻辑
});
}
}
五、关键注意事项(避坑指南)
-
手动回滚的核心:setRollbackOnly () 该方法是 **「标记回滚」**,不是立即回滚,仅将事务状态标记为回滚,方法执行完成后由 Spring 自动执行回滚操作(符合 Spring 事务的生命周期,推荐使用 );无需手动调用
commit()/rollback(),TransactionTemplate会自动处理。 -
异常的自动回滚 若事务内抛出未捕获的 RuntimeException/Error ,
TransactionTemplate会自动标记事务回滚 ,无需手动调用setRollbackOnly();若捕获了异常,需重新抛出 或手动标记回滚,否则事务会正常提交(这是最常见的坑)。 -
只读事务的使用 仅对纯查询操作 设置
setReadOnly(true),数据库会对只读事务做优化(如不加写锁);若只读事务内执行插入 / 更新 / 删除操作,会抛出数据库异常(不同数据库异常不同)。 -
超时时间的单位
setTimeout(int)的单位是秒 ,不是毫秒!比如setTimeout(3)表示事务超时时间为 3 秒,超过则抛出TransactionTimedOutException并回滚。 -
与声明式事务的兼容
TransactionTemplate可以和@Transactional混合使用,但不推荐 :两者的事务上下文相互独立,可能导致事务嵌套问题;若已使用TransactionTemplate,则无需再加@Transactional注解。
六、TransactionTemplate 核心优势
对比其他编程式事务方案(继承TransactionAspectSupport、直接使用PlatformTransactionManager),TransactionTemplate的核心优势:
- 无侵入:业务类无需继承 / 实现任何 Spring 类,符合依赖注入(DI)思想,便于单元测试;
- 封装性好:屏蔽了事务开启、提交、回滚的底层细节,只需关注业务逻辑;
- 代码简洁:通过 lambda 表达式简化代码,比直接使用事务管理器少写大量模板代码;
- 灵活性高:支持自定义事务属性、多数据源、有 / 无返回值,覆盖绝大多数编程式事务场景。
总结
TransactionTemplate是 Spring 编程式事务的最优解,核心使用要点可总结为 3 点:
- 基础使用 :注入默认
TransactionTemplate,通过executeWithoutResult(无返回值)/execute(有返回值)执行事务,setRollbackOnly()实现自定义规则回滚; - 属性自定义 :通过构造方法手动创建
TransactionTemplate,设置传播行为、隔离级别、超时时间等属性,满足特殊业务需求; - 多数据源 :为每个数据源创建独立的事务管理器和
TransactionTemplate,通过@Qualifier注入指定模板实现隔离; - 避坑关键:异常捕获后需重新抛出 / 手动标记回滚,只读事务仅用于查询,超时时间单位为秒。
核心使用原则 :当@Transactional声明式事务无法满足自定义业务规则回滚 等灵活控制需求时,优先使用TransactionTemplate实现编程式事务。
方式二:继承TransactionAspectSupport(简洁兜底)
掌握 **TransactionAspectSupport的完整事务管理用法,它是 Spring 事务的底层核心基础类,也是声明式事务的兜底方案,核心优势是 继承后直接调用父类方法 **,无需注入额外 Bean(如TransactionTemplate/ 事务管理器),就能实现手动精细控制事务 ,最适合结合@Transactional注解使用(注解开启事务 + 父类方法控制回滚),也支持纯编程式的全流程事务控制。
下面从核心定位 & 前置条件 、推荐用法(结合 @Transactional) 、纯编程式用法(无注解) 、核心 API 详解 、避坑注意事项五个维度讲解,所有示例均为 Spring Boot 可直接运行的实战代码,兼顾简洁性和实用性。
一、核心定位 & 前置条件
- 核心定位
TransactionAspectSupport是 Spring所有事务切面的父类 (如声明式事务的核心拦截器TransactionInterceptor),封装了事务开启、提交、回滚、传播行为处理等所有底层核心逻辑 ,它的设计初衷就是为了让开发者能复用 Spring 的事务逻辑,快速实现编程式事务。
- 轻侵入:业务类只需继承该类,即可获得所有事务操作能力;
- 无缝兼容:可直接结合
@Transactional使用,注解负责配置事务属性 (传播行为、隔离级别等),父类方法负责手动控制事务(标记回滚、获取事务状态); - 兜底方案:当
@Transactional的自动回滚(基于异常)无法满足需求时(如自定义业务规则回滚),它是最简洁的兜底方式。
- 前置条件(Spring Boot 自动满足)
使用前无需额外配置,Spring Boot 已自动完成核心准备:
- 引入数据库 + 持久层依赖 (如 MyBatis-Plus/MyBatis + 数据源),Spring Boot 自动创建
DataSourceTransactionManager(事务管理器); @SpringBootApplication注解已包含@EnableTransactionManagement,开启了 Spring 事务注解支持;- 业务类需被 Spring 管理(加
@Service/@Component等注解)。
必备依赖示例(和常规 Spring Boot 数据库项目一致):
xml
XML
<!-- MyBatis-Plus + 德鲁伊数据源 + MySQL -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.20</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
二、推荐用法:结合 @Transactional(99% 实战场景)
这是开发中最常用的方式 ,核心思路是:用@Transactional注解开启事务并配置事务属性(传播行为、隔离级别、回滚异常等),用TransactionAspectSupport的父类方法手动控制事务(标记回滚、获取事务状态)。
这种方式兼顾了@Transactional的简洁性 和编程式事务的灵活性 ,无需手动处理事务开启 / 提交,只需关注自定义规则的手动回滚,是最优解。
核心步骤
- 业务类继承
TransactionAspectSupport,获得父类的事务操作方法; - 业务方法上加
@Transactional,配置常规事务属性(如rollbackFor = Exception.class); - 方法内通过 **
this.currentTransactionStatus()** 获取当前事务状态(TransactionStatus); - 根据自定义业务规则 ,调用
status.setRollbackOnly()标记事务回滚(核心操作)。
实战代码(核心场景:自定义规则无异常回滚)
模拟创建订单 场景:订单金额为 0 时,无异常但需要手动回滚事务 (@Transactional无法实现,因为它仅基于异常回滚),同时保证订单和日志的原子性(要么都成功,要么都回滚)。
java
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import java.math.BigDecimal;
@Service
// 步骤1:继承TransactionAspectSupport,获得事务操作能力
public class OrderService extends TransactionAspectSupport {
@Autowired
private OrderMapper orderMapper; // 持久层Mapper(MyBatis/MyBatis-Plus)
@Autowired
private LogMapper logMapper; // 日志持久层,保证和订单同事务
/**
* 步骤2:加@Transactional注解,配置事务属性(和常规声明式事务一致)
* 传播行为REQUIRED(默认)、对所有Exception回滚、非只读
*/
@Transactional(rollbackFor = Exception.class)
public void createOrder(Order order) {
try {
// 1. 执行业务操作:同一会话,共享事务
orderMapper.insert(order); // 插入订单
Log orderLog = new Log();
orderLog.setOrderId(order.getId());
orderLog.setContent("创建订单:" + order.getOrderNo());
logMapper.insert(orderLog); // 插入订单日志
// 2. 核心:自定义业务规则,无异常手动标记回滚
if (order.getAmount().compareTo(BigDecimal.ZERO) == 0) {
// 步骤3+4:获取事务状态 → 标记为仅回滚
TransactionStatus status = this.currentTransactionStatus();
status.setRollbackOnly();
System.out.println("订单金额为0,手动标记事务回滚");
return; // 无需抛出异常,直接返回即可
}
// 3. 无异常+无手动回滚 → 事务由@Transactional自动提交
} catch (Exception e) {
// 4. 异常场景:手动标记回滚(也可省略,@Transactional会自动回滚)
this.currentTransactionStatus().setRollbackOnly();
throw new RuntimeException("创建订单失败,事务回滚", e);
// 必须抛出异常(或让异常向上传播),否则Spring可能无法感知
}
}
}
简化写法(一行代码标记回滚)
currentTransactionStatus()可以直接链式调用setRollbackOnly(),省略临时变量,让代码更简洁:
java
// 自定义规则回滚:一行代码完成
if (order.getAmount().compareTo(BigDecimal.ZERO) == 0) {
this.currentTransactionStatus().setRollbackOnly();
System.out.println("订单金额为0,手动标记事务回滚");
return;
}
自定义 @Transactional 属性(传播行为 / 隔离级别等)
可以根据业务需求,在@Transactional中配置传播行为、隔离级别、超时时间、只读 等属性,TransactionAspectSupport会自动复用这些配置,无需额外处理:
// 自定义事务属性:新建独立事务+读已提交+3秒超时+非只读
@Transactional(
rollbackFor = Exception.class,
propagation = Propagation.REQUIRES_NEW, // 独立事务,主事务回滚不影响
isolation = Isolation.READ_COMMITTED, // 隔离级别:读已提交
timeout = 3 // 超时时间:3秒,超过则强制回滚
)
public void createOrderWithCustomProp(Order order) {
// 业务逻辑和之前一致,手动回滚方式不变
if (order.getAmount().compareTo(BigDecimal.ZERO) == 0) {
this.currentTransactionStatus().setRollbackOnly();
return;
}
orderMapper.insert(order);
}
三、纯编程式用法(无 @Transactional,了解即可)
TransactionAspectSupport也支持纯编程式事务 (无需@Transactional注解),手动控制事务的开启→业务→提交 / 回滚 全流程,但这种方式需要手动注入事务管理器,代码稍繁琐,不如TransactionTemplate简洁,仅作了解(实战中不推荐)。
核心步骤
- 注入
DataSourceTransactionManager(事务管理器); - 手动创建事务定义 (
DefaultTransactionDefinition),配置传播行为、隔离级别等属性; - 通过父类方法
this.createTransactionIfNecessary()手动开启事务,获取事务状态; - 执行业务逻辑,根据规则手动提交 / 回滚事务。
实战代码
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import java.math.BigDecimal;
@Service
public class OrderService extends TransactionAspectSupport {
@Autowired
private OrderMapper orderMapper;
@Autowired
private LogMapper logMapper;
// 步骤1:注入事务管理器
@Autowired
private DataSourceTransactionManager transactionManager;
/**
* 纯编程式事务:无@Transactional,手动控制全流程
*/
public void createOrderWithoutAnnotation(Order order) {
// 步骤2:创建事务定义,配置属性
TransactionDefinition txDef = new DefaultTransactionDefinition() {{
setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
}};
// 步骤3:手动开启事务,获取事务状态(父类方法)
TransactionStatus status = this.createTransactionIfNecessary(transactionManager, txDef, "createOrder");
try {
// 执行业务操作
orderMapper.insert(order);
Log orderLog = new Log();
orderLog.setOrderId(order.getId());
logMapper.insert(orderLog);
// 自定义规则回滚
if (order.getAmount().compareTo(BigDecimal.ZERO) == 0) {
this.completeTransactionAfterThrowing(status, new RuntimeException("金额为0"));
System.out.println("订单金额为0,手动回滚");
return;
}
// 步骤4:无异常,手动提交事务(父类方法)
this.commitTransactionAfterReturning(status);
} catch (Exception e) {
// 异常,手动回滚事务(父类方法)
this.completeTransactionAfterThrowing(status, e);
throw new RuntimeException("创建订单失败", e);
}
}
}
四、核心 API 详解(父类受保护方法)
TransactionAspectSupport提供了多个受保护的核心方法 (子类可直接通过this调用),这些方法是事务控制的核心,重点掌握常用的 4 个即可:
| 方法名 | 核心作用 | 适用场景 |
|---|---|---|
currentTransactionStatus() |
获取当前生效的事务状态 (TransactionStatus) |
结合@Transactional时,手动标记回滚的核心入口(最常用) |
createTransactionIfNecessary(...) |
根据事务管理器和事务定义,手动开启事务 | 纯编程式事务,手动创建事务 |
commitTransactionAfterReturning(TransactionStatus) |
根据事务状态,提交事务 | 纯编程式事务,无异常时手动提交 |
completeTransactionAfterThrowing(TransactionStatus, Throwable) |
根据事务状态和异常,回滚事务 | 纯编程式事务,异常时手动回滚 |
关键子 API:TransactionStatus(事务状态)
currentTransactionStatus()返回的TransactionStatus是事务控制的核心接口 ,其中最常用的方法就是:
java
// 标记事务为「仅回滚」,这是手动回滚的核心(非立即回滚,方法执行完后Spring自动回滚)
status.setRollbackOnly();
其他常用辅助方法(了解即可):
isRollbackOnly():判断事务是否已被标记为回滚;isCompleted():判断事务是否已完成(提交 / 回滚);hasSavepoint():判断事务是否有保存点(嵌套事务)。
五、避坑注意事项(必看)
使用TransactionAspectSupport时,容易踩的坑都和Spring 事务的底层原理相关,重点记住 5 点,避免事务不生效 / 回滚失败:
- 必须保证 @Transactional 的事务上下文生效
结合@Transactional使用时,该注解的所有生效规则依然适用,最常见的坑是:
- 方法为非 public (
@Transactional仅对 public 方法生效),导致事务未开启,调用currentTransactionStatus()会抛出 **NoTransactionException**; - 同一个类中内部调用 有
@Transactional的方法,AOP 代理无法拦截,事务未开启,同样抛出NoTransactionException。
解决方案:
- 保证事务方法为public;
- 内部调用时,注入自身代理对象 或通过
ApplicationContext获取代理对象,再调用事务方法。
- 调用 currentTransactionStatus () 前必须有活跃事务
currentTransactionStatus()只能在有活跃事务的上下文中调用 (即方法被@Transactional标记,或手动开启了事务),否则会抛出NoTransactionException: No transaction aspect-managed TransactionStatus in scope。
错误示例(无 @Transactional,直接调用):
java
// 无@Transactional,无活跃事务
public void test() {
this.currentTransactionStatus(); // 抛出NoTransactionException
}
- setRollbackOnly () 是「标记回滚」,非立即回滚
该方法不会立即执行回滚操作 ,仅将事务状态标记为「仅回滚」,当方法执行完成后,Spring 会自动根据该状态执行回滚,这是符合 Spring 事务生命周期的设计(推荐使用)。
无需手动调用commit()/rollback(),@Transactional会自动处理提交 / 回滚。
- 异常捕获后必须重新抛出(或手动标记回滚)
如果在事务方法内捕获了异常但不重新抛出 ,也不手动调用setRollbackOnly(),Spring 无法感知异常,会默认提交事务(这是所有 Spring 事务的通用坑)。
错误示例(捕获异常不处理):
java
@Transactional(rollbackFor = Exception.class)
public void createOrder(Order order) {
try {
orderMapper.insert(order);
int i = 1 / 0; // 模拟异常
} catch (Exception e) {
e.printStackTrace(); // 仅打印,不抛出、不标记回滚
}
// Spring感知不到异常,事务会提交!
}
正确做法 :捕获异常后重新抛出 ,或手动标记回滚。
- 多数据源场景:指定事务管理器
多数据源场景下,需要在@Transactional中显式指定对应的事务管理器 Bean 名称,否则 Spring 会使用默认的事务管理器,导致事务不生效:
java
// 多数据源:指定事务管理器为mysql2TransactionManager
@Transactional(
rollbackFor = Exception.class,
transactionManager = "mysql2TransactionManager"
)
public void createOrder(Order order) {
// 手动回滚方式不变
this.currentTransactionStatus().setRollbackOnly();
}
六、与 TransactionTemplate 的对比(选型指南)
TransactionAspectSupport和TransactionTemplate都是 Spring 编程式事务的主流方案,很多开发者会纠结选型,这里直接给出清晰的对比和选型建议:
| 特性 | TransactionAspectSupport |
TransactionTemplate |
|---|---|---|
| 侵入性 | 轻侵入(业务类需继承该类) | 无侵入(仅注入 Bean,无需继承 / 实现) |
| 代码简洁度 | 极高(一行代码currentTransactionStatus().setRollbackOnly()) |
高(lambda 表达式封装,需写模板代码) |
| 依赖注入 | 无需注入任何事务相关 Bean | 需注入TransactionTemplate(或手动创建) |
| 纯编程式支持 | 支持(代码繁琐,不推荐) | 支持(封装好,代码简洁,推荐) |
| 单元测试友好性 | 稍差(继承了 Spring 的类,需要模拟父类方法) | 极好(无侵入,可轻松 mock 注入的 Bean) |
| 适用场景 | 1. 结合@Transactional实现 自定义规则回滚(99% 场景) 2. 快速开发,不想注入额外 Bean |
1. 纯编程式事务(无@Transactional) 2. 追求无侵入、高可测试性的场景 3. 多数据源纯编程式事务 |
选型核心建议
- 99% 的实战场景 :优先使用
TransactionAspectSupport + @Transactional,兼顾简洁性和灵活性,一行代码实现自定义规则回滚,开发效率最高; - 纯编程式事务(无 @Transactional) :优先使用
TransactionTemplate,无侵入、封装好、代码更简洁,是 Spring 官方推荐方案; - 多数据源纯编程式事务 :必须使用
TransactionTemplate(为每个数据源创建独立的TransactionTemplate,注入指定模板即可,更清晰); - 单元测试要求高 :使用
TransactionTemplate(无侵入,mock 更简单)。
七、总结
TransactionAspectSupport是 Spring 事务的底层兜底工具类,核心使用要点可总结为 3 个核心:
- 推荐用法 :业务类继承该类 + 方法加 **
@Transactional,通过this.currentTransactionStatus().setRollbackOnly()实现自定义业务规则的手动回滚 **,这是实战中最常用的方式; - 核心坑点 :保证
@Transactional的事务上下文生效(public 方法、无内部调用),调用currentTransactionStatus()前必须有活跃事务,异常捕获后需重新抛出 / 手动标记回滚; - 选型原则 :仅当需要结合 @Transactional 实现灵活回滚 时,使用
TransactionAspectSupport;纯编程式事务优先使用TransactionTemplate。
一句话核心 :TransactionAspectSupport是@Transactional的最佳拍档,解决了声明式事务 "仅能基于异常回滚" 的痛点,让声明式事务也能支持自定义业务规则的精细控制。
方式三:直接使用PlatformTransactionManager(最底层,最高灵活性)
掌握 **PlatformTransactionManager的事务管理用法,它是 Spring 事务的 最底层核心接口 **,所有 Spring 事务(包括@Transactional、TransactionTemplate、TransactionAspectSupport)最终都通过它的实现类完成事务开启、提交、回滚 的实际操作。它的核心优势是灵活性极致 ,能完全手动控制事务的全生命周期,适合极复杂的事务场景(如跨分支精细控制、多数据源手动协调、嵌套事务定制等),但需要手动编写事务生命周期的所有代码,无任何封装。
这是 Spring 编程式事务的最底层实现 ,直接操作事务管理器的开启 / 提交 / 回滚 方法,灵活性最高 (可完全自定义事务的全生命周期),但代码最繁琐 ,适合极复杂的事务控制场景(如跨多数据源、事务嵌套精细控制)。
下面从核心定位 & 前置条件 、核心 API 详解 、基础单数据源实战 、自定义事务属性 、多数据源事务控制 、避坑注意事项六个维度讲解,所有示例均为 Spring Boot 可直接运行的实战代码,兼顾原理和实用性。
一、核心定位 & 前置条件
- 核心定位
- Spring 事务的底层入口 :
PlatformTransactionManager是 Spring 事务的顶级管理器接口 ,无具体实现,Spring 为不同持久层技术提供了对应的实现类,日常开发最常用的是DataSourceTransactionManager(适配 JDBC/MyBatis/MyBatis-Plus,基于关系型数据库的数据源事务); - 全手动控制 :无任何封装,需要开发者手动完成事务定义→开启→执行业务→提交 / 回滚 的全流程,是 Spring 编程式事务中灵活性最高的方式;
- 适用于复杂场景 :常规业务不推荐使用(代码繁琐),仅适用于
@Transactional、TransactionTemplate无法满足的极复杂事务控制场景(如多数据源事务手动协调、事务嵌套精细定制、根据多分支条件动态提交 / 回滚等)。
- 前置条件(Spring Boot 自动满足)
使用前无需额外复杂配置,Spring Boot 已自动完成核心准备:
- 引入数据库 + 持久层依赖 (如 MyBatis-Plus/MyBatis + 数据源),Spring Boot 会自动创建
DataSourceTransactionManager实例(默认事务管理器); @SpringBootApplication已包含@EnableTransactionManagement,开启 Spring 事务支持;- 业务类被 Spring 管理(加
@Service/@Component),直接注入事务管理器即可使用。
必备依赖示例(和常规 Spring Boot 数据库项目一致):
java
<!-- MyBatis-Plus + 德鲁伊数据源 + MySQL -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.20</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
- 常用实现类
PlatformTransactionManager的实现类与持久层技术强绑定,日常开发仅需关注以下 2 个:
| 实现类 | 适配场景 | 核心作用 |
|---|---|---|
DataSourceTransactionManager |
JDBC/MyBatis/MyBatis-Plus(关系型数据库) | 基于数据库数据源的本地事务管理(99% 的日常场景) |
JtaTransactionManager |
分布式事务(跨数据源 / 跨服务) | 基于 JTA 规范的分布式事务管理 |
二、核心 API 详解
PlatformTransactionManager接口仅有3 个核心方法,覆盖事务的全生命周期,这是手动管理事务的基础,必须掌握:
java
public interface PlatformTransactionManager {
// 1. 开启事务:根据事务定义,创建并返回当前事务状态
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
// 2. 提交事务:根据事务状态,提交已完成的事务
void commit(TransactionStatus status) throws TransactionException;
// 3. 回滚事务:根据事务状态,回滚异常/需要回滚的事务
void rollback(TransactionStatus status) throws TransactionException;
}
配套核心类:
TransactionDefinition:事务定义接口,用于配置事务属性 (传播行为、隔离级别、超时时间、只读),日常使用其实现类DefaultTransactionDefinition;TransactionStatus:事务状态接口,用于标识当前事务的状态 (是否开启、是否标记回滚、是否完成等),是getTransaction的返回值,也是commit/rollback的入参,核心方法setRollbackOnly()(标记事务仅回滚)。
三、基础单数据源实战(核心场景)
这是PlatformTransactionManager的基础使用方式 ,适配 99% 的单数据源复杂事务场景,核心步骤是 **「定义事务→开启事务→执行业务→手动提交 / 回滚」,模拟创建订单 ** 场景:订单金额为 0 时手动回滚,异常时也回滚,保证订单和日志的原子性。
核心步骤
- 注入
DataSourceTransactionManager(Spring Boot 自动配置的默认事务管理器); - 创建
DefaultTransactionDefinition,配置事务属性(默认属性可直接 new,无需额外设置); - 调用
getTransaction()开启事务,获取TransactionStatus(事务状态); - 执行业务逻辑(数据库操作);
- 根据自定义业务规则 / 异常 ,调用
rollback()手动回滚或commit()手动提交。
实战代码
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import java.math.BigDecimal;
@Service
public class OrderService {
// 步骤1:注入默认事务管理器(Spring Boot自动配置)
@Autowired
private DataSourceTransactionManager transactionManager;
@Autowired
private OrderMapper orderMapper; // 持久层Mapper(MyBatis/MyBatis-Plus)
@Autowired
private LogMapper logMapper; // 日志Mapper,与订单同事务
/**
* PlatformTransactionManager基础使用:单数据源手动控制事务全生命周期
*/
public void createOrder(Order order) {
// 步骤2:创建事务定义,使用默认属性(可自定义,后续讲解)
TransactionDefinition txDef = new DefaultTransactionDefinition();
// 步骤3:开启事务,获取事务状态(核心:事务的唯一标识,后续提交/回滚都依赖它)
TransactionStatus status = transactionManager.getTransaction(txDef);
try {
// 步骤4:执行业务操作(所有操作共享同一个事务,原子性保证)
orderMapper.insert(order); // 插入订单
Log orderLog = new Log();
orderLog.setOrderId(order.getId());
orderLog.setContent("创建订单:" + order.getOrderNo());
logMapper.insert(orderLog); // 插入订单日志
// 自定义业务规则:订单金额为0,手动回滚事务
if (order.getAmount().compareTo(BigDecimal.ZERO) == 0) {
// 步骤5-1:手动回滚(立即执行回滚操作,非标记)
transactionManager.rollback(status);
System.out.println("订单金额为0,事务已手动回滚");
return;
}
// 步骤5-2:无异常+无自定义回滚,手动提交事务(立即执行提交)
transactionManager.commit(status);
System.out.println("订单创建成功,事务已手动提交");
} catch (Exception e) {
// 步骤5-3:异常场景,强制手动回滚(必须加,否则事务会挂起,占用数据库连接)
transactionManager.rollback(status);
System.out.println("业务执行异常,事务已手动回滚");
throw new RuntimeException("创建订单失败", e); // 异常向上传播
}
}
}
核心关键点
TransactionStatus是核心标识 :开启事务后返回的status是当前事务的唯一状态标识 ,后续的commit/rollback必须传入同一个status,否则会操作错误的事务;- 手动回滚 / 提交是「立即执行」 :与
TransactionTemplate、TransactionAspectSupport的setRollbackOnly()(标记回滚,方法结束后执行)不同,transactionManager.rollback/commit(status)会立即执行数据库的回滚 / 提交操作; - 异常必须回滚 :如果业务抛出异常但未调用
rollback(),事务会一直处于挂起状态 ,占用数据库连接,最终导致连接池耗尽,这是最核心的坑 ,必须在catch块中强制回滚。
四、自定义事务属性
默认的DefaultTransactionDefinition使用默认事务属性 (传播行为 REQUIRED、隔离级别 DEFAULT、永不超时、非只读),若需要自定义(如独立事务、指定隔离级别、设置超时),可通过DefaultTransactionDefinition的 set 方法配置,覆盖默认值,适配特殊业务场景。
常用事务属性配置(全量)
java
// 创建事务定义,自定义所有属性
TransactionDefinition txDef = new DefaultTransactionDefinition();
// 1. 传播行为:新建独立事务(主事务回滚不影响此事务),默认REQUIRED
txDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
// 2. 隔离级别:读已提交(解决脏读),默认DEFAULT(跟随数据库)
txDef.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
// 3. 事务超时时间:3秒(超过则抛出TransactionTimedOutException),单位为秒,默认-1(永不超时)
txDef.setTimeout(3);
// 4. 只读事务:仅适用于纯查询操作,数据库会做优化,写操作设置会报错,默认false
txDef.setReadOnly(false);
// 5. 事务名称:用于日志/监控标识,非必须
((DefaultTransactionDefinition) txDef).setName("createOrder-Tx");
实战:自定义传播行为(REQUIRES_NEW)
模拟订单创建 + 日志记录 场景,要求日志记录为独立事务 (即使订单事务回滚,日志仍需提交),通过PROPAGATION_REQUIRES_NEW实现:
java
/**
* 自定义事务属性:日志记录使用独立事务(REQUIRES_NEW)
*/
public void createOrderWithLog(Order order) {
// 1. 订单事务:默认属性(REQUIRED)
TransactionDefinition orderTxDef = new DefaultTransactionDefinition();
TransactionStatus orderStatus = transactionManager.getTransaction(orderTxDef);
try {
orderMapper.insert(order);
System.out.println("订单插入成功,等待提交");
// 2. 日志事务:自定义传播行为REQUIRES_NEW(新建独立事务)
TransactionDefinition logTxDef = new DefaultTransactionDefinition();
logTxDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus logStatus = transactionManager.getTransaction(logTxDef);
try {
Log orderLog = new Log();
orderLog.setOrderId(order.getId());
logMapper.insert(orderLog);
transactionManager.commit(logStatus); // 日志事务独立提交
System.out.println("日志插入成功,独立事务已提交");
} catch (Exception e) {
transactionManager.rollback(logStatus); // 日志事务独立回滚
throw new RuntimeException("日志记录失败", e);
}
// 模拟订单业务异常,触发订单事务回滚
if (order.getAmount().compareTo(BigDecimal.ZERO) == 0) {
transactionManager.rollback(orderStatus);
System.out.println("订单金额为0,订单事务回滚");
return;
}
transactionManager.commit(orderStatus);
} catch (Exception e) {
transactionManager.rollback(orderStatus);
throw new RuntimeException("创建订单失败", e);
}
}
执行结果 :订单金额为 0 时,订单事务回滚 ,但日志事务已独立提交(日志数据保留),实现了事务隔离。
五、多数据源场景:手动控制不同数据源的事务
多数据源场景是PlatformTransactionManager的经典适用场景 ,核心思路是为每个数据源创建独立的事务管理器 ,然后分别通过对应的事务管理器手动控制各自的事务(开启、提交、回滚),实现不同数据源的事务隔离。
步骤 1:配置多数据源和对应事务管理器
首先在配置类中创建多个数据源 和对应的DataSourceTransactionManager,每个事务管理器绑定一个数据源,Spring Boot 不会自动配置多数据源,需手动定义:
java
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
public class MultiDatasourceTxConfig {
// 数据源1:主库(订单库),@Primary标记默认数据源
@Primary
@Bean("orderDataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.order")
public DataSource orderDataSource() {
return DruidDataSourceBuilder.create().build();
}
// 数据源2:从库(用户库)
@Bean("userDataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.user")
public DataSource userDataSource() {
return DruidDataSourceBuilder.create().build();
}
// 事务管理器1:绑定订单库数据源,@Primary标记默认事务管理器
@Primary
@Bean("orderTxManager")
public DataSourceTransactionManager orderTxManager(@Primary DataSource orderDataSource) {
return new DataSourceTransactionManager(orderDataSource);
}
// 事务管理器2:绑定用户库数据源
@Bean("userTxManager")
public DataSourceTransactionManager userTxManager(DataSource userDataSource) {
return new DataSourceTransactionManager(userDataSource);
}
}
步骤 2:配置文件添加多数据源配置(application.yml)
XML
spring:
datasource:
druid:
# 订单库(主库)
order:
url: jdbc:mysql://localhost:3306/order_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# 用户库(从库)
user:
url: jdbc:mysql://localhost:3306/user_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
步骤 3:业务层注入多事务管理器,手动控制各自事务
业务中分别通过orderTxManager(订单库)和userTxManager(用户库)控制不同数据源的事务,实现跨数据源的手动事务管理:
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
@Service
public class MultiDatasourceOrderService {
// 注入订单库事务管理器
@Autowired
@Qualifier("orderTxManager")
private DataSourceTransactionManager orderTxManager;
// 注入用户库事务管理器
@Autowired
@Qualifier("userTxManager")
private DataSourceTransactionManager userTxManager;
@Autowired
private OrderMapper orderMapper; // 绑定订单库的Mapper
@Autowired
private UserMapper userMapper; // 绑定用户库的Mapper
/**
* 多数据源事务:手动控制订单库和用户库的独立事务
*/
public void createOrderAndBindUser(Order order, Long userId) {
// 1. 订单库事务:开启并控制
TransactionDefinition orderTxDef = new DefaultTransactionDefinition();
TransactionStatus orderStatus = orderTxManager.getTransaction(orderTxDef);
// 2. 用户库事务:开启并控制
TransactionDefinition userTxDef = new DefaultTransactionDefinition();
TransactionStatus userStatus = userTxManager.getTransaction(userTxDef);
try {
// 操作订单库
orderMapper.insert(order);
// 操作用户库(绑定订单和用户)
userMapper.bindOrder(userId, order.getId());
// 无异常,分别提交两个数据源的事务
orderTxManager.commit(orderStatus);
userTxManager.commit(userStatus);
System.out.println("跨数据源操作成功,两个事务均提交");
} catch (Exception e) {
// 有异常,分别回滚两个数据源的事务(必须全量回滚,避免数据不一致)
orderTxManager.rollback(orderStatus);
userTxManager.rollback(userStatus);
System.out.println("跨数据源操作异常,两个事务均回滚");
throw new RuntimeException("创建订单并绑定用户失败", e);
}
}
}
关键点 :多数据源手动事务中,异常时必须回滚所有数据源的事务 ,否则会导致跨数据源数据不一致 (这是分布式事务的基础问题,PlatformTransactionManager仅能实现本地事务的手动协调,无法解决分布式事务的最终一致性)。
六、避坑注意事项(必看,核心)
PlatformTransactionManager是无封装的底层 API,使用时容易因忽略细节导致事务异常、数据库连接泄漏、数据不一致,重点记住 6 个核心坑点:
- 异常必须手动回滚,否则连接泄漏
这是最常见、最严重的坑 :如果业务抛出异常但未在catch块中调用rollback(status),事务会一直处于挂起状态 ,数据库连接不会释放,最终导致连接池耗尽 ,整个应用无法操作数据库。强制要求 :必须在 try-catch 块中使用 ,catch块中强制调用 rollback (status),无论任何异常都要回滚。
TransactionStatus必须一一对应
开启事务时返回的status与后续的commit/rollback必须一一对应 ,不能混用不同事务的status,否则会抛出IllegalTransactionStateException(非法事务状态异常)。错误示例:
java
// 订单事务status
TransactionStatus orderStatus = orderTxManager.getTransaction(txDef);
// 用户事务status
TransactionStatus userStatus = userTxManager.getTransaction(txDef);
// 错误:用用户事务的status操作订单事务的回滚
orderTxManager.rollback(userStatus);
- 只读事务不能执行写操作
设置txDef.setReadOnly(true)的事务为只读事务 ,数据库会对其做优化(如不加写锁、走查询缓存),若在只读事务中执行插入 / 更新 / 删除 操作,会抛出数据库异常(不同数据库异常不同,MySQL 会抛出SQLException)。使用场景 :仅纯查询操作可设置只读,写操作必须保持默认false。
- 超时时间单位是「秒」,不是毫秒
txDef.setTimeout(int)的参数单位是秒 ,而非毫秒,比如setTimeout(3)表示事务超时时间为 3 秒,超过则 Spring 会抛出TransactionTimedOutException,并需要手动回滚。
- 避免事务嵌套的不当使用
PlatformTransactionManager支持事务嵌套,但需根据传播行为合理设计:
- 传播行为为
REQUIRED:嵌套事务会加入父事务,父事务回滚则子事务也回滚; - 传播行为为
REQUIRES_NEW:嵌套事务会新建独立事务 ,与父事务完全隔离,父事务回滚不影响子事务。注意:嵌套事务过多会导致数据库连接占用过多,需谨慎使用。
- 多数据源事务仅能实现「本地事务协调」,非分布式事务
PlatformTransactionManager的实现类都是本地事务管理器 ,多数据源场景下仅能实现多个本地事务的手动开启 / 提交 / 回滚 ,无法解决分布式事务的最终一致性问题 (如一个数据源提交成功,另一个数据源回滚失败)。解决方案 :若需要真正的分布式事务,需使用 Seata、Saga、TCC 等分布式事务框架,而非单纯的PlatformTransactionManager。
七、与其他事务方案的对比(选型指南)
PlatformTransactionManager与@Transactional、TransactionTemplate、TransactionAspectSupport的核心差异在于封装程度 和灵活性,以下是清晰的对比和选型建议:
| 实现方式 | 封装 程度 | 灵活性 | 代码 简洁度 | 适用场景 |
|---|---|---|---|---|
@Transactional |
完全 封装 | 低 | 极高 | 90% 的常规业务(声明式事务,开发首选) |
TransactionTemplate |
高度 封装 | 中 | 高 | 常规编程式事务(Spring 官方推荐) |
TransactionAspectSupport |
半封装 | 中 | 极高 | 结合@Transactional实现自定义回滚 |
PlatformTransactionManager |
无封装 | 极致 | 极低 | 极复杂事务场景(多数据源手动协调、事务嵌套定制、跨分支精细控制) |
选型核心建议
- 常规业务 :优先使用
@Transactional,开发效率最高,代码最简洁,无需关注事务底层; - 常规编程式事务 :使用
TransactionTemplate,高度封装,无侵入,兼顾灵活性和简洁性; - 结合
@Transactional实现自定义回滚 :使用TransactionAspectSupport,一行代码实现手动标记回滚; - 极复杂事务场景 (如多数据源手动协调、事务全生命周期定制、嵌套事务精细控制):仅使用
PlatformTransactionManager,这是唯一能满足极致灵活性的方式。
八、总结
PlatformTransactionManager是 Spring 事务的底层核心,所有 Spring 事务的最终操作都由它完成,核心使用要点可总结为 3 个核心:
- 核心步骤 :
注入事务管理器(如DataSourceTransactionManager)
→ 创建TransactionDefinition(事务属性)
→getTransaction()开启事务
→ 执行业务
→commit()/rollback()手动提交 / 回滚 ,
全程手动控制; - 核心 API :仅 3 个方法
getTransaction()/commit()/rollback(),
配套TransactionDefinition(事务属性)和TransactionStatus(事务状态); - 核心坑点 :必须在 try-catch 中使用,异常强制回滚(避免连接泄漏),
TransactionStatus一一对应,只读事务不执行写操作,多数据源仅能协调本地事务; - 选型原则 :仅当
@Transactional、TransactionTemplate无法满足极复杂的事务控制需求 时,才使用PlatformTransactionManager,常规业务绝不使用(代码繁琐,易出错)。
一句话核心 :PlatformTransactionManager是 Spring 事务的 **"底层发动机"**,为所有上层事务方案提供动力,开发者直接使用时,需具备扎实的事务底层知识,否则极易踩坑。
总结
Spring 编程式事务的核心是3 种实现方式 + 1 个核心控制类(TransactionStatus),核心要点如下:
- 首选
TransactionTemplate:无侵入、封装好,是 Spring 官方推荐的编程式事务方案,支持无返回值 / 有返回值、自定义事务属性; - 简洁方案用
TransactionAspectSupport:继承后直接调用父类方法,结合@Transactional使用更高效; - 复杂场景用
PlatformTransactionManager:直接操作事务管理器,实现事务全生命周期的自定义控制; - 手动回滚核心 :
TransactionStatus.setRollbackOnly()(标记回滚),异常时 Spring 会自动回滚; - 选型原则 :声明式事务满足不了的灵活控制场景,才用编程式事务,日常开发优先用
@Transactional。