学习Spring框架下的分布式事务

分布式事务使用场景

假设一个应用内存在多个需要协同工作的资源Resource(比如多个数据库DB,消息队列MQ等),他们需要协同修改并保证“一起成功,或者一起失败”,就是分布式事务的典型应用场景。

试想,一个电商平台的下单功能,把钱从用户账户扣除,同时下一个物流单的场景:

//伪代码
public void OrderService () {
        // 进行如下操作
        1. start database transaction A
        2. sql,把钱从用户账户扣除
        3. start 物流 shipment transaction B
        4. 下物流单
        5. commit 物流 shipment transaction B
        // 物流单成功/出错了
        6. commit database transaction A
    }

如果物流单(资源B)成功,数据库(资源A)修改也提交
如果资源B出错了回滚,资源A修改也回滚。
在多个资源的情况下,需要一个协调者,这里称为事务管理器(Transaction Manager),来协调例子里的资源A和资源B的协同沟通。

分布式事务XA
以下定义引用自[1]. XA : XA是一个规范或是一个事务的协议。XA协议由Tuxedo首先提出的,并交给X/Open组织,作为资源管理器(Resource Manager)与事务管理器(Transaction Manager)的接口标准。

XA规范定义了:
1. TransactionManager : 可以通过管理多个ResourceManager来管理多个Resouce,也就是管理多个资源
2. XAResource : 针对数据资源封装的一个接口,支持分布式资源的封装(可回滚、提交)
3. 两段式提交 : XA使用两阶段提交来保证所有资源同时提交或回滚任何特定的事务

两阶段提交(Two-Phase Commit Model)
举例
假设有多个Resource资源作为投票者(R1,R2,...Rn),他们在同一个分布式事务中。
有一个管理者TransactionManager,负责统计阶段一的执行结果并决策阶段二。

阶段一:R1执行后,会通知管理者R1成功,并block住自己的改变,注意!它并没有真正提交这个事务,等待管理者通知它,这就是阶段一;R2~Rn也是如此,改变后在等待管理者的通知

阶段二:管理者TransactionManager把参与分布式事务的所有Resource结果收集完毕,如果R1~Rn全部执行成功,管理者通知所有资源R1,R2...Rn去真正执行提交commit;如果有任何一个执行失败,则通知所有资源执行回滚rollback

两阶段提交

即多个Resource被ResourceManager封装后,和同一个管理者TransactionManager沟通,并执行一起提交或者一起回滚。

在Spring中实现分布式事务
Spring中提供了事务管理器TransactionManager的具体类是PlatformTransactionManager,分布式资源会交给这个PlatformTransactionManager来管理,要求是:分布式资源XA Resource必须被包装成支持分布式的ResourceManager, 资源由ResourceManager来PlatformTransactionManager沟通。

根据参考资料[4]Spring官方文档描述,Spring支持使用声明式的@Transactional来使用事务,其实这个注释相当于编程式地使用PlatformTransactionManager。

public class UserService{
    @Transactional
    public void query(){
        //business logic
    }
}

对于上面这段伪代码,相当于编程式方式这么写:

public class UserService{
    @Autowired
    private PlatformTransactionManager txMgr;
    
    public void query(){
      //伪代码,用来示意,@Transactional相当于以下功能
      try{
        txMgr.beginTransaction();
        //business logic成功,不抛出checked ex就会提交commit()
        txMgr.commit();
      }  catch(Exception checkedException) {
        //默认情况下,捕获到checkedException,就会自动回滚
        txMgr.rollback();
      }
 
    }
 
}

上面的try-catch和@Transactional作用完全相当,也就是说Spring AOP的这个注释,实现了对该线程内的调用栈自动捕获受检查异常(checked exception),当然也可以捕获特定异常才回滚,建议这段看官方文档补充细节。

值得注意的是,Spring的Transaction会和调用栈的当前线程紧紧绑定在一起,也就是说一个事务是从属于当前线程的,在调用栈上抛出了异常就会回滚,这样的回滚操作逻辑。

数据源本身对分布式的支持要求
如果是数据库,那么数据库的ResourceManager要支持分布式的提交和回滚,同时DB本身也应该有厂商提供的XA数据源,根据参考资料[3],复制粘贴了原博客对H2内存数据库的XA数据源获取代码:

org.h2.jdbcx.JdbcDataSource xaDataSource=new org.h2.jdbcx.JdbcDataSource();        
xaDataSource.setUser("sa");
xaDataSource.setPassword("");        
xaDataSource.setURL("jdbc:h2:tcp://localhost/~/test");
javax.sql.XAConnection dbXAConnection=xaDataSource.getXAConnection();
javax.transaction.xa.XAResource dbXAResource=dbXAConnection.getXAResource();
java.sql.Connection conn=dbXAConnection.getConnection();

在Tomcat这种轻量级的Web容器内使用分布式事务,根据参考资料[2],可以借助于第三方软件jotm(Java Open Transaction Manager )和AtomikosTransactionsEssentials实现,在spring中分布式事务是通过jta(jotm,atomikos)来进行实现。

参考资料:

[1]分布式事务实践(三)--Spring的全局事务JTA - 简书

[2]Spring如何支持分布式事务 - codedot - 博客园

[3]JTA 三 (XADataSource) - 独行侠的个人空间 - OSCHINA - 中文开源技术交流社区

[4]Data Access

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值