事务抽象与编程式事务

引言

转账扣款必须“要么都成功、要么都回滚”。Spring 不重新发明事务,而是抽象出统一的事务管理接口,屏蔽 JDBC/JPA/Hibernate 的差异,业务代码只依赖抽象。本章介绍抽象核心 PlatformTransactionManager 与编程式用法(TransactionTemplate),声明式(@Transactional)下一章讲。

核心概念

  • 事务四特性 ACID:原子性、一致性、隔离性、持久性(具体语义由数据库保证)。
  • PlatformTransactionManager(org.springframework.transaction):事务抽象的核心接口,三个方法决定边界:getTransaction(TransactionDefinition) 开启/加入、commit(TransactionStatus) 提交、rollback(TransactionStatus) 回滚。
  • 常见实现:DataSourceTransactionManager(单数据源 JDBC/MyBatis 场景最常用)、JpaTransactionManagerHibernateTransactionManager;多数据源/分布式需 JTA 或分布式事务方案(以官方文档为准)。
  • TransactionDefinition:携带传播行为、隔离级别、超时、只读标志(第 15 章详述)。
  • 编程式两种写法:直接用 PlatformTransactionManager 手工 begin/commit/rollback;或 TransactionTemplate——模板方法,回调里抛运行时异常自动回滚,代码更简洁。
  • 事务底层资源绑定:实现通过线程绑定(如 DataSourceTransactionManager 绑定数据库连接到当前线程),保证同一线程内多次 DAO 调用处于同一事务。

代码示例

// 1) 装配:数据源 + 事务管理器(生产用连接池数据源)
@Configuration
public class TxConfig {
    @Bean
    public DataSource dataSource() {
        return new org.springframework.jdbc.datasource.DriverManagerDataSource(
                "jdbc:mysql://localhost:3306/shop", "root", "secret");
    }
    @Bean
    public PlatformTransactionManager txManager(DataSource ds) {
        return new DataSourceTransactionManager(ds);
    }
}

// 2) TransactionTemplate 编程式事务
@Service
public class AccountService {
    private final TransactionTemplate txTemplate; // 默认 REQUIRED 传播

    public AccountService(PlatformTransactionManager txManager) {
        this.txTemplate = new TransactionTemplate(txManager);
    }

    public void transfer(long fromId, long toId, long amount) {
        txTemplate.executeWithoutResult(status -> {   // 抛异常自动回滚
            jdbc.update("UPDATE account SET balance = balance - ? WHERE id = ?",
                    amount, fromId);
            jdbc.update("UPDATE account SET balance = balance + ? WHERE id = ?",
                    amount, toId);
            // 若中间抛 RuntimeException,两行更新一起回滚
        });
    }
}

注意点

  • 事务管理器必须与 DAO 使用同一个数据源,否则事务管不住你的 SQL(经典错配,见第 16 章)。
  • TransactionTemplate 默认对 RuntimeException/Error 回滚,受检异常不自动回滚(可在回调内 catch 后调用 status.setRollbackOnly() 或抛出运行时异常)。
  • 编程式事务把边界逻辑写进业务代码,适合事务边界在方法内部的少数场景;绝大多数场景声明式更清晰。
  • getTransaction 返回的 TransactionStatus 代表“当前参与的事务”,commit/rollback 前先判 status.isNewTransaction() 更严谨。
  • 连接池(如 HikariCP)由外部库提供;示例中的 DriverManagerDataSource 仅演示,生产勿用(每次新建连接)。

小结

Spring 事务 = 抽象接口(PlatformTransactionManager)+ 边界描述(TransactionDefinition)+ 两种用法(手工/模板)。TransactionTemplate 让编程式事务只剩“回调里写业务”这一步。掌握资源线程绑定思想后,下一章的 @Transactional 只是把边界声明挪到注解上。

笔记加载中…