Sring事务详解之02.如何使用编程式事务?

掌握 Spring 中编程式事务 的完整使用方法,编程式事务是相对于@Transactional声明式事务的灵活方案,适合需要手动精细控制事务的场景(比如根据自定义业务规则决定回滚、事务内多分支条件控制等)。

Spring 提供了3 种主流的编程式事务实现方式 ,按推荐程度 + 使用简洁度 排序,从最推荐(无侵入、封装性好)最底层(灵活性最高) 依次讲解,所有示例均基于 Spring Boot(自动配置事务管理器,无需额外配置),兼顾原理可直接运行的实战代码

前置基础

  1. Spring Boot 会自动根据数据源创建DataSourceTransactionManager(事务管理器),无需手动配置 Bean;
  2. 编程式事务的核心是 **TransactionStatus** 接口:用于标记事务状态(如setRollbackOnly()手动标记回滚),是所有编程式事务的控制入口;
  3. 核心抽象:PlatformTransactionManager(顶级事务管理器)、TransactionDefinition(事务定义,如传播行为、隔离级别)、TransactionStatus(事务状态),三者关系:事务管理器根据事务定义创建事务,返回事务状态用于控制

方式一:使用TransactionTemplate(最推荐)

核心特点

  • Spring 官方推荐 ,基于模板方法模式封装,无需手动处理事务的开启 / 提交 / 回滚,只需关注业务逻辑;无需手动处理事务生命周期,同时支持自定义事务属性(传播行为、隔离级别等)和有 / 无返回值场景。
  • 无侵入:业务类无需继承 / 实现任何 Spring 类,符合依赖注入(DI)思想;
  • 封装性好 :自动处理异常回滚,代码简洁,是开发中最常用的编程式事务方案

核心方法

TransactionTemplate的核心方法execute(TransactionCallback<T>),支持有返回值无返回值两种重载:

  1. execute(TransactionCallback<T>):有返回值,适合需要从事务内返回业务数据的场景;
  2. executeWithoutResult(Consumer<TransactionStatus>):无返回值,适合纯操作型业务(如插入 / 更新)。

实战示例

  1. 基础依赖(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>
  1. 核心 API

TransactionTemplate的核心是两个执行方法 ,覆盖无返回值有返回值 所有业务场景,事务控制的核心是TransactionStatus接口(手动标记回滚的入口):

方法 作用 适用场景
executeWithoutResult(Consumer<TransactionStatus>) 无返回值执行事务 插入 / 更新 / 删除等纯操作型业务(最常用
execute(TransactionCallback<T>) 有返回值执行事务 插入后返回主键、查询 + 操作后返回结果等
TransactionStatus.setRollbackOnly() 手动标记事务回滚 自定义业务规则回滚(无异常场景的核心)
  1. 默认事务属性

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);
            // ... 业务逻辑
        });
    }
}

五、关键注意事项(避坑指南)

  1. 手动回滚的核心:setRollbackOnly () 该方法是 **「标记回滚」**,不是立即回滚,仅将事务状态标记为回滚,方法执行完成后由 Spring 自动执行回滚操作(符合 Spring 事务的生命周期,推荐使用 );无需手动调用commit()/rollback()TransactionTemplate会自动处理。

  2. 异常的自动回滚 若事务内抛出未捕获的 RuntimeException/ErrorTransactionTemplate自动标记事务回滚 ,无需手动调用setRollbackOnly();若捕获了异常,需重新抛出手动标记回滚,否则事务会正常提交(这是最常见的坑)。

  3. 只读事务的使用 仅对纯查询操作 设置setReadOnly(true),数据库会对只读事务做优化(如不加写锁);若只读事务内执行插入 / 更新 / 删除操作,会抛出数据库异常(不同数据库异常不同)。

  4. 超时时间的单位 setTimeout(int)的单位是 ,不是毫秒!比如setTimeout(3)表示事务超时时间为 3 秒,超过则抛出TransactionTimedOutException并回滚。

  5. 与声明式事务的兼容 TransactionTemplate可以和@Transactional混合使用,但不推荐 :两者的事务上下文相互独立,可能导致事务嵌套问题;若已使用TransactionTemplate,则无需再加@Transactional注解。

六、TransactionTemplate 核心优势

对比其他编程式事务方案(继承TransactionAspectSupport、直接使用PlatformTransactionManager),TransactionTemplate的核心优势:

  1. 无侵入:业务类无需继承 / 实现任何 Spring 类,符合依赖注入(DI)思想,便于单元测试;
  2. 封装性好:屏蔽了事务开启、提交、回滚的底层细节,只需关注业务逻辑;
  3. 代码简洁:通过 lambda 表达式简化代码,比直接使用事务管理器少写大量模板代码;
  4. 灵活性高:支持自定义事务属性、多数据源、有 / 无返回值,覆盖绝大多数编程式事务场景。

总结

TransactionTemplate是 Spring 编程式事务的最优解,核心使用要点可总结为 3 点:

  1. 基础使用 :注入默认TransactionTemplate,通过executeWithoutResult(无返回值)/execute(有返回值)执行事务,setRollbackOnly()实现自定义规则回滚;
  2. 属性自定义 :通过构造方法手动创建TransactionTemplate,设置传播行为、隔离级别、超时时间等属性,满足特殊业务需求;
  3. 多数据源 :为每个数据源创建独立的事务管理器和TransactionTemplate,通过@Qualifier注入指定模板实现隔离;
  4. 避坑关键:异常捕获后需重新抛出 / 手动标记回滚,只读事务仅用于查询,超时时间单位为秒。

核心使用原则 :当@Transactional声明式事务无法满足自定义业务规则回滚 等灵活控制需求时,优先使用TransactionTemplate实现编程式事务。

方式二:继承TransactionAspectSupport(简洁兜底)

掌握 **TransactionAspectSupport的完整事务管理用法,它是 Spring 事务的底层核心基础类,也是声明式事务的兜底方案,核心优势是 继承后直接调用父类方法 **,无需注入额外 Bean(如TransactionTemplate/ 事务管理器),就能实现手动精细控制事务 ,最适合结合@Transactional注解使用(注解开启事务 + 父类方法控制回滚),也支持纯编程式的全流程事务控制。

下面从核心定位 & 前置条件推荐用法(结合 @Transactional)纯编程式用法(无注解)核心 API 详解避坑注意事项五个维度讲解,所有示例均为 Spring Boot 可直接运行的实战代码,兼顾简洁性和实用性。

一、核心定位 & 前置条件

  1. 核心定位

TransactionAspectSupport是 Spring所有事务切面的父类 (如声明式事务的核心拦截器TransactionInterceptor),封装了事务开启、提交、回滚、传播行为处理等所有底层核心逻辑 ,它的设计初衷就是为了让开发者能复用 Spring 的事务逻辑,快速实现编程式事务。

  • 轻侵入:业务类只需继承该类,即可获得所有事务操作能力;
  • 无缝兼容:可直接结合@Transactional使用,注解负责配置事务属性 (传播行为、隔离级别等),父类方法负责手动控制事务(标记回滚、获取事务状态);
  • 兜底方案:当@Transactional的自动回滚(基于异常)无法满足需求时(如自定义业务规则回滚),它是最简洁的兜底方式。
  1. 前置条件(Spring Boot 自动满足)

使用前无需额外配置,Spring Boot 已自动完成核心准备:

  1. 引入数据库 + 持久层依赖 (如 MyBatis-Plus/MyBatis + 数据源),Spring Boot 自动创建DataSourceTransactionManager(事务管理器);
  2. @SpringBootApplication注解已包含@EnableTransactionManagement开启了 Spring 事务注解支持
  3. 业务类需被 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简洁性 和编程式事务的灵活性 ,无需手动处理事务开启 / 提交,只需关注自定义规则的手动回滚,是最优解。

核心步骤

  1. 业务类继承TransactionAspectSupport,获得父类的事务操作方法;
  2. 业务方法上加@Transactional,配置常规事务属性(如rollbackFor = Exception.class);
  3. 方法内通过 **this.currentTransactionStatus()** 获取当前事务状态(TransactionStatus);
  4. 根据自定义业务规则 ,调用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简洁,仅作了解(实战中不推荐)。

核心步骤

  1. 注入DataSourceTransactionManager(事务管理器);
  2. 手动创建事务定义DefaultTransactionDefinition),配置传播行为、隔离级别等属性;
  3. 通过父类方法this.createTransactionIfNecessary()手动开启事务,获取事务状态;
  4. 执行业务逻辑,根据规则手动提交 / 回滚事务。

实战代码

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 点,避免事务不生效 / 回滚失败:

  1. 必须保证 @Transactional 的事务上下文生效

结合@Transactional使用时,该注解的所有生效规则依然适用,最常见的坑是:

  • 方法为非 public@Transactional仅对 public 方法生效),导致事务未开启,调用currentTransactionStatus()会抛出 **NoTransactionException**;
  • 同一个类中内部调用@Transactional的方法,AOP 代理无法拦截,事务未开启,同样抛出NoTransactionException

解决方案

  • 保证事务方法为public
  • 内部调用时,注入自身代理对象 或通过ApplicationContext获取代理对象,再调用事务方法。
  1. 调用 currentTransactionStatus () 前必须有活跃事务

currentTransactionStatus()只能在有活跃事务的上下文中调用 (即方法被@Transactional标记,或手动开启了事务),否则会抛出NoTransactionException: No transaction aspect-managed TransactionStatus in scope

错误示例(无 @Transactional,直接调用):

java 复制代码
// 无@Transactional,无活跃事务
public void test() {
    this.currentTransactionStatus(); // 抛出NoTransactionException
}
  1. setRollbackOnly () 是「标记回滚」,非立即回滚

该方法不会立即执行回滚操作 ,仅将事务状态标记为「仅回滚」,当方法执行完成后,Spring 会自动根据该状态执行回滚,这是符合 Spring 事务生命周期的设计(推荐使用)。

无需手动调用commit()/rollback()@Transactional会自动处理提交 / 回滚。

  1. 异常捕获后必须重新抛出(或手动标记回滚)

如果在事务方法内捕获了异常但不重新抛出 ,也不手动调用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感知不到异常,事务会提交!
}

正确做法 :捕获异常后重新抛出 ,或手动标记回滚

  1. 多数据源场景:指定事务管理器

多数据源场景下,需要在@Transactional显式指定对应的事务管理器 Bean 名称,否则 Spring 会使用默认的事务管理器,导致事务不生效:

java 复制代码
// 多数据源:指定事务管理器为mysql2TransactionManager
@Transactional(
        rollbackFor = Exception.class,
        transactionManager = "mysql2TransactionManager"
)
public void createOrder(Order order) {
    // 手动回滚方式不变
    this.currentTransactionStatus().setRollbackOnly();
}

六、与 TransactionTemplate 的对比(选型指南)

TransactionAspectSupportTransactionTemplate都是 Spring 编程式事务的主流方案,很多开发者会纠结选型,这里直接给出清晰的对比和选型建议

特性 TransactionAspectSupport TransactionTemplate
侵入性 轻侵入(业务类需继承该类 无侵入(仅注入 Bean,无需继承 / 实现)
代码简洁度 极高(一行代码currentTransactionStatus().setRollbackOnly() 高(lambda 表达式封装,需写模板代码)
依赖注入 无需注入任何事务相关 Bean 需注入TransactionTemplate(或手动创建)
纯编程式支持 支持(代码繁琐,不推荐) 支持(封装好,代码简洁,推荐)
单元测试友好性 稍差(继承了 Spring 的类,需要模拟父类方法) 极好(无侵入,可轻松 mock 注入的 Bean)
适用场景 1. 结合@Transactional实现 自定义规则回滚(99% 场景) 2. 快速开发,不想注入额外 Bean 1. 纯编程式事务(无@Transactional) 2. 追求无侵入、高可测试性的场景 3. 多数据源纯编程式事务

选型核心建议

  1. 99% 的实战场景优先使用TransactionAspectSupport + @Transactional,兼顾简洁性和灵活性,一行代码实现自定义规则回滚,开发效率最高;
  2. 纯编程式事务(无 @Transactional)优先使用TransactionTemplate,无侵入、封装好、代码更简洁,是 Spring 官方推荐方案;
  3. 多数据源纯编程式事务必须使用TransactionTemplate (为每个数据源创建独立的TransactionTemplate,注入指定模板即可,更清晰);
  4. 单元测试要求高使用TransactionTemplate(无侵入,mock 更简单)。

七、总结

TransactionAspectSupport是 Spring 事务的底层兜底工具类,核心使用要点可总结为 3 个核心:

  1. 推荐用法 :业务类继承该类 + 方法加 **@Transactional,通过this.currentTransactionStatus().setRollbackOnly()实现自定义业务规则的手动回滚 **,这是实战中最常用的方式;
  2. 核心坑点 :保证@Transactional的事务上下文生效(public 方法、无内部调用),调用currentTransactionStatus()前必须有活跃事务,异常捕获后需重新抛出 / 手动标记回滚;
  3. 选型原则 :仅当需要结合 @Transactional 实现灵活回滚 时,使用TransactionAspectSupport;纯编程式事务优先使用TransactionTemplate

一句话核心TransactionAspectSupport@Transactional最佳拍档,解决了声明式事务 "仅能基于异常回滚" 的痛点,让声明式事务也能支持自定义业务规则的精细控制。

方式三:直接使用PlatformTransactionManager(最底层,最高灵活性)

掌握 **PlatformTransactionManager的事务管理用法,它是 Spring 事务的 最底层核心接口 **,所有 Spring 事务(包括@TransactionalTransactionTemplateTransactionAspectSupport)最终都通过它的实现类完成事务开启、提交、回滚 的实际操作。它的核心优势是灵活性极致 ,能完全手动控制事务的全生命周期,适合极复杂的事务场景(如跨分支精细控制、多数据源手动协调、嵌套事务定制等),但需要手动编写事务生命周期的所有代码,无任何封装。

这是 Spring 编程式事务的最底层实现 ,直接操作事务管理器的开启 / 提交 / 回滚 方法,灵活性最高 (可完全自定义事务的全生命周期),但代码最繁琐 ,适合极复杂的事务控制场景(如跨多数据源、事务嵌套精细控制)。

下面从核心定位 & 前置条件核心 API 详解基础单数据源实战自定义事务属性多数据源事务控制避坑注意事项六个维度讲解,所有示例均为 Spring Boot 可直接运行的实战代码,兼顾原理和实用性。

一、核心定位 & 前置条件

  1. 核心定位
  • Spring 事务的底层入口PlatformTransactionManager是 Spring 事务的顶级管理器接口 ,无具体实现,Spring 为不同持久层技术提供了对应的实现类,日常开发最常用的是DataSourceTransactionManager(适配 JDBC/MyBatis/MyBatis-Plus,基于关系型数据库的数据源事务);
  • 全手动控制 :无任何封装,需要开发者手动完成事务定义→开启→执行业务→提交 / 回滚 的全流程,是 Spring 编程式事务中灵活性最高的方式;
  • 适用于复杂场景 :常规业务不推荐使用(代码繁琐),仅适用于@TransactionalTransactionTemplate无法满足的极复杂事务控制场景(如多数据源事务手动协调、事务嵌套精细定制、根据多分支条件动态提交 / 回滚等)。
  1. 前置条件(Spring Boot 自动满足)

使用前无需额外复杂配置,Spring Boot 已自动完成核心准备:

  1. 引入数据库 + 持久层依赖 (如 MyBatis-Plus/MyBatis + 数据源),Spring Boot 会自动创建DataSourceTransactionManager实例(默认事务管理器);
  2. @SpringBootApplication已包含@EnableTransactionManagement,开启 Spring 事务支持;
  3. 业务类被 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>
  1. 常用实现类

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;
}

配套核心类

  1. TransactionDefinition :事务定义接口,用于配置事务属性 (传播行为、隔离级别、超时时间、只读),日常使用其实现类DefaultTransactionDefinition
  2. TransactionStatus :事务状态接口,用于标识当前事务的状态 (是否开启、是否标记回滚、是否完成等),是getTransaction的返回值,也是commit/rollback的入参,核心方法setRollbackOnly()(标记事务仅回滚)。

三、基础单数据源实战(核心场景)

这是PlatformTransactionManager基础使用方式 ,适配 99% 的单数据源复杂事务场景,核心步骤是 **「定义事务→开启事务→执行业务→手动提交 / 回滚」,模拟创建订单 ** 场景:订单金额为 0 时手动回滚,异常时也回滚,保证订单和日志的原子性。

核心步骤

  1. 注入DataSourceTransactionManager(Spring Boot 自动配置的默认事务管理器);
  2. 创建DefaultTransactionDefinition,配置事务属性(默认属性可直接 new,无需额外设置);
  3. 调用getTransaction()开启事务,获取TransactionStatus(事务状态);
  4. 执行业务逻辑(数据库操作);
  5. 根据自定义业务规则 / 异常 ,调用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); // 异常向上传播
        }
    }
}

核心关键点

  1. TransactionStatus是核心标识 :开启事务后返回的status是当前事务的唯一状态标识 ,后续的commit/rollback必须传入同一个status,否则会操作错误的事务;
  2. 手动回滚 / 提交是「立即执行」 :与TransactionTemplateTransactionAspectSupportsetRollbackOnly()(标记回滚,方法结束后执行)不同,transactionManager.rollback/commit(status)立即执行数据库的回滚 / 提交操作
  3. 异常必须回滚 :如果业务抛出异常但未调用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 个核心坑点:

  1. 异常必须手动回滚,否则连接泄漏

这是最常见、最严重的坑 :如果业务抛出异常但未在catch块中调用rollback(status),事务会一直处于挂起状态 ,数据库连接不会释放,最终导致连接池耗尽 ,整个应用无法操作数据库。强制要求必须在 try-catch 块中使用catch块中强制调用 rollback (status),无论任何异常都要回滚。

  1. TransactionStatus必须一一对应

开启事务时返回的status与后续的commit/rollback必须一一对应 ,不能混用不同事务的status,否则会抛出IllegalTransactionStateException(非法事务状态异常)。错误示例

java 复制代码
// 订单事务status
TransactionStatus orderStatus = orderTxManager.getTransaction(txDef);
// 用户事务status
TransactionStatus userStatus = userTxManager.getTransaction(txDef);
// 错误:用用户事务的status操作订单事务的回滚
orderTxManager.rollback(userStatus);
  1. 只读事务不能执行写操作

设置txDef.setReadOnly(true)的事务为只读事务 ,数据库会对其做优化(如不加写锁、走查询缓存),若在只读事务中执行插入 / 更新 / 删除 操作,会抛出数据库异常(不同数据库异常不同,MySQL 会抛出SQLException)。使用场景 :仅纯查询操作可设置只读,写操作必须保持默认false

  1. 超时时间单位是「秒」,不是毫秒

txDef.setTimeout(int)的参数单位是 ,而非毫秒,比如setTimeout(3)表示事务超时时间为 3 秒,超过则 Spring 会抛出TransactionTimedOutException,并需要手动回滚。

  1. 避免事务嵌套的不当使用

PlatformTransactionManager支持事务嵌套,但需根据传播行为合理设计:

  • 传播行为为REQUIRED:嵌套事务会加入父事务,父事务回滚则子事务也回滚;
  • 传播行为为REQUIRES_NEW:嵌套事务会新建独立事务 ,与父事务完全隔离,父事务回滚不影响子事务。注意:嵌套事务过多会导致数据库连接占用过多,需谨慎使用。
  1. 多数据源事务仅能实现「本地事务协调」,非分布式事务

PlatformTransactionManager的实现类都是本地事务管理器 ,多数据源场景下仅能实现多个本地事务的手动开启 / 提交 / 回滚 ,无法解决分布式事务的最终一致性问题 (如一个数据源提交成功,另一个数据源回滚失败)。解决方案 :若需要真正的分布式事务,需使用 Seata、Saga、TCC 等分布式事务框架,而非单纯的PlatformTransactionManager

七、与其他事务方案的对比(选型指南)

PlatformTransactionManager@TransactionalTransactionTemplateTransactionAspectSupport的核心差异在于封装程度灵活性,以下是清晰的对比和选型建议:

实现方式 封装 程度 灵活性 代码 简洁度 适用场景
@Transactional 完全 封装 极高 90% 的常规业务(声明式事务,开发首选)
TransactionTemplate 高度 封装 常规编程式事务(Spring 官方推荐)
TransactionAspectSupport 半封装 极高 结合@Transactional实现自定义回滚
PlatformTransactionManager 无封装 极致 极低 极复杂事务场景(多数据源手动协调、事务嵌套定制、跨分支精细控制)

选型核心建议

  1. 常规业务优先使用@Transactional,开发效率最高,代码最简洁,无需关注事务底层;
  2. 常规编程式事务使用TransactionTemplate,高度封装,无侵入,兼顾灵活性和简洁性;
  3. 结合@Transactional实现自定义回滚使用TransactionAspectSupport,一行代码实现手动标记回滚;
  4. 极复杂事务场景 (如多数据源手动协调、事务全生命周期定制、嵌套事务精细控制):仅使用PlatformTransactionManager,这是唯一能满足极致灵活性的方式。

八、总结

PlatformTransactionManager是 Spring 事务的底层核心,所有 Spring 事务的最终操作都由它完成,核心使用要点可总结为 3 个核心:

  1. 核心步骤
    注入事务管理器(如DataSourceTransactionManager
    → 创建TransactionDefinition(事务属性)
    getTransaction()开启事务
    → 执行业务
    commit()/rollback()手动提交 / 回滚

    全程手动控制;
  2. 核心 API :仅 3 个方法getTransaction()/commit()/rollback()
    配套TransactionDefinition(事务属性)和TransactionStatus(事务状态);
  3. 核心坑点 :必须在 try-catch 中使用,异常强制回滚(避免连接泄漏),
    TransactionStatus一一对应,只读事务不执行写操作,多数据源仅能协调本地事务;
  4. 选型原则 :仅当@TransactionalTransactionTemplate无法满足极复杂的事务控制需求 时,才使用PlatformTransactionManager,常规业务绝不使用(代码繁琐,易出错)。

一句话核心PlatformTransactionManager是 Spring 事务的 **"底层发动机"**,为所有上层事务方案提供动力,开发者直接使用时,需具备扎实的事务底层知识,否则极易踩坑。

总结

Spring 编程式事务的核心是3 种实现方式 + 1 个核心控制类(TransactionStatus,核心要点如下:

  1. 首选TransactionTemplate:无侵入、封装好,是 Spring 官方推荐的编程式事务方案,支持无返回值 / 有返回值、自定义事务属性;
  2. 简洁方案用TransactionAspectSupport :继承后直接调用父类方法,结合@Transactional使用更高效;
  3. 复杂场景用PlatformTransactionManager:直接操作事务管理器,实现事务全生命周期的自定义控制;
  4. 手动回滚核心TransactionStatus.setRollbackOnly()(标记回滚),异常时 Spring 会自动回滚;
  5. 选型原则 :声明式事务满足不了的灵活控制场景,才用编程式事务,日常开发优先用@Transactional
相关推荐
笨蛋不要掉眼泪13 小时前
Redis哨兵机制全解析:原理、配置与实战故障转移演示
java·数据库·redis·缓存·bootstrap
驾数者13 小时前
Flink SQL实时数仓实战:基于Flink SQL的完整项目案例
sql·flink·linq
Coder_Boy_13 小时前
基于SpringAI的在线考试系统-整体架构优化设计方案
java·数据库·人工智能·spring boot·架构·ddd
小草cys14 小时前
在 openEuler 上安装 DDE 图形桌面环境(适用于华为鲲鹏服务器/PC)
运维·服务器
草履虫建模19 小时前
力扣算法 1768. 交替合并字符串
java·开发语言·算法·leetcode·职场和发展·idea·基础
天才奇男子21 小时前
HAProxy高级功能全解析
linux·运维·服务器·微服务·云原生
fen_fen1 天前
Oracle建表语句示例
数据库·oracle
qq_297574671 天前
【实战教程】SpringBoot 实现多文件批量下载并打包为 ZIP 压缩包
java·spring boot·后端
老毛肚1 天前
MyBatis插件原理及Spring集成
java·spring·mybatis