Seata 1.5.2 源码学习(事务执行)()

  本篇文章为你整理了Seata 1.5.2 源码学习(事务执行)()的详细内容,包含有 Seata 1.5.2 源码学习(事务执行),希望能帮助你了解 Seata 1.5.2 源码学习(事务执行)。

  关于全局事务的执行,虽然之前的文章中也有所涉及,但不够细致,今天再深入的看一下事务的整个执行过程是怎样的。

  1. TransactionManager

  io.seata.core.model.TransactionManager是事务管理器,它定义了一个全局事务的相关操作

  DefaultTransactionManager是TransactionManager的一个实现类

  可以看到,所有操作(开启、提交、回滚、查询状态、上报)都是调用TmNettyRemotingClient#sendSyncRequest()方法向TC发请求

  2. GlobalTransaction

  DefaultGlobalTransaction实现了GlobalTransaction,它代表一个全局事务

  有两件事情需要留意,一是transactionManager是什么? 二是GlobalTransactionRole又是什么?

  采用静态内部类的形式来构造单例,还记得DefaultRMHandler和DefaultResourceManager也都是通过静态内部类的形式构造单例

  3. TransactionalTemplate

  TransactionalTemplate是全局事务执行模板,所有业务逻辑都在其定义的模板方法中执行

  io.seata.tm.api.TransactionalTemplate#execute()

  现在整个过程清楚了,首先根据事务传播特性来创建一个事务对象,然后开启事务,执行业务逻辑处理,最后提交事务,如果业务执行过程中抛异常,则回滚事务。

  现在有一个问题,什么情况下会进入TransactionalTemplate#execute(),或者说什么时候调用该方法?

  要回答这个问题,又得从io.seata.spring.annotation.GlobalTransactionScanner说起,这个前面已经说过了,想了解的可以再看看之前那篇 https:///cjsblog/p/16866796.html

  从GlobalTransactionScanner说起就太长了,直接快进到GlobalTransactionalInterceptor拦截器吧

  当被调用的方法上有@GlobalTransactional注解时,就会被拦截,从而进入GlobalTransactionalInterceptor#invoke(),在invoke()里会调用GlobalTransactionalInterceptor#handleGlobalTransaction(),于是顺利进入TransactionalTemplate#execute()

  也就是说,当进入第一个@GlobalTransactional方法时,此时全局事务为空,于是创建一个角色为“GlobalTransactionRole.Launcher”的DefaultGlobalTransaction。当方法内部又调用了另一个@GlobalTransactional方法,于是再创建一个角色为“GlobalTransactionRole.Participant”的DefaultGlobalTransaction。以此类推,后面的都是事务“参与者”。

  好了,现在事务已经创建,接下来就可以开启事务并执行业务逻辑处理了

  可以看到,只有角色为“GlobalTransactionRole.Launcher”的线程才可以执行事务的开启提交回滚操作,而且这些操作的底层都是调用TransactionManager中的方法,最终是调用TmNettyRemotingClient#sendSyncRequest()方法向TC发送同步请求

  最后,看一下什么时候回滚

  catch捕获到异常就回滚

  以上这些说的都是TM,因为是TM在控制整个全局事务的执行,至于RM本地事务的执行要看io.seata.rm.datasource.ConnectionProxy,这个在之前都讲过了

  4. GlobalLockTemplate

  GlobalLockTemplate是全局锁模板,是需要全局锁的本地事务的一个执行器模板

  那么,在哪里用这个"TX_LOCK"线程变量呢?在BaseTransactionalExecutor#execute()

  默认ConnectionContext中isGlobalLockRequire为false

  现在就很清晰了,当方法上加了@GlobalLock注解后,进入GlobalLockTemplate#execute(),在当前线程上绑定局部变量TX_LOCK=true。当本地事务提交的时候,上下文(ConnectionContext)中isGlobalLockRequire为true,于是给TC发请求查询锁,如果这些数据没有被任何事务加锁,或者被当前事务加锁,则都算获取到锁了,如果被别的事务加锁了,则算获取锁失败。

  总结一下锁互斥,分这么几种情况:

  两个@GlobalTransactional方法之间,会在注册分支事务的时候检查全局锁,注册成功(获取锁成功)才能提交

  两个@GlobalLock方法之间,会在事务提交前检查全局锁,获取到锁才能提交

  @GlobalTransactional方法与@GlobalLock方法之间,都是在提交前,一个是分支注册检查锁,一个是直接检查锁

  还有一个问题,哪些数据会被加锁呢?这就要从io.seata.rm.datasource.exec.ExecuteTemplate#execute()说起了

  长话短说,什么样的数据加锁取决于数据库,以及SQL语句,自行理解一下吧

  5. 总结

  1、Seata到底是如何实现分布式事务的?

  首先,每个业务系统都要引入seata的jar包,因此每个业务系统都是一个seata client,于是数据源被seata代理,同时所有方法添加拦截器,对加了@GlobalTransactional的方法进行拦截处理;

  其次,进入事务方法后,按照模板方法定义,在try...catch...finally中先创建事务并开启,接着执行业务处理,如果抛异常则回滚,如果顺利执行完成,则提交;

  再次,被调用的远程服务在其本地开启事务并执行,将业务处理和undo_log放在同一个事务中,然后向TC注册分支事务,成功后提交本地事务并向TC报告分支状态

  最后,业务顺利执行完或抛异常后TM向TC发请求可以提交或回滚全局事务了,TC向所有已注册的分支事务发送提交或回滚请求

  总之,数据源代理和全局事务扫描是seata实现分布式事务的基础,而TM做的事情就是控制事务的执行,RM做的事就是处理好本地事务的执行,TC是协调器

  2、Seata实现的全局事务,它的事务隔离级别是怎样的?会不会出现脏读、幻读、不可重复读?

  先看脏读,在全局事务提交之前,分支事务早已提交,因此,默认情况下,其它的事务是可以读取到当前未提交的全局事务的数据的,故而,默认情况下会发生脏读。

  举个例子,假设现在有一个全局事务A还没提交,但是其中的分支事务A1已经提交,A2还在没提交,这个时候另一个全局事务B是可以读取到A1已经提交的数据的,也就是在全局事务B中读到了还未提交的全局事务A的数据,这就是脏读。

  那么,如何避免脏读呢?

  思路是这样的:首先要让Seata意识到这个SQL语句执行时锁,光知道需要锁还不行,还得让它在执行的时候检查是否获取到锁了。一个SELECT语句需要锁就是将其改写成SELECT ... FOR UPDATE的形式,检查锁的话@GlobalTransactional或@GlobalLock都可以办到。于是,解决版本就有两个:

  SELECT ... FOR UPDATE + @GlobalTransactional

  SELECT ... FOR UPDATE + @GlobalLock

  综上所述,分支事务在提交前先进行分支注册获取全局锁,在全局事务提交成功后释放全局锁。此时,其它全局事务可以读取到已提交的分支事务的数据,但这是当前全局事务还未提交,于是出现脏读。办法也很简单,首先select加for update,其次业务方法加@GlobalTransactional或@GlobalLock注解。

  同理,默认是可能出现幻读和不可重复读的,它俩属于是脏写,究其原因还是因为跨数据库了,seata搞了个全局锁,这就相当于将业务中几个不同的数据库看成一个数据库,全局锁就相当于这个大数据库中的行级锁,因此解决办法还是一样

  不得不说,Seata真的是一个优秀的分布式事务框架

  3、AT模式、TCC模式、Saga模式、XA模式的区别

  AT模式是基于支持本地事务的关系型数据库

  TCC模式不依赖于数据库的事务支持,另外TCC没有全局锁,也就没有锁竞争,故而效率比AT模式高

  Saga模式是seata提供的长事务解决方案

  XA模式以 XA 协议的机制来管理分支事务的一种事务模式

  

  以上就是Seata 1.5.2 源码学习(事务执行)()的详细内容,想要了解更多 Seata 1.5.2 源码学习(事务执行)的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: