位置: IT常识 - 正文

Seata 1.5.2 源码学习(seata1.3.0配置)

编辑:rootadmin
文章有点长,我决定用半个小时来和你分享~😂 废话不多说,上代码。。。 基于Seata 1.5.2,项目中用 seata-spring-boot-starter 1. SeataDataSourceAutoConfiguration SeataDataSourceAutoConfiguration ...

推荐整理分享Seata 1.5.2 源码学习(seata1.3.0配置),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:seastar源码分析,seatam,seastar源码分析,seata1.3.0配置,seafile源码,seafile源码,seastar源码分析,seata at源码,内容如对您有帮助,希望把文章链接给更多的朋友!

文章有点长,我决定用半个小时来和你分享~? 废话不多说,上代码。。。

基于Seata 1.5.2,项目中用 seata-spring-boot-starter

1. SeataDataSourceAutoConfiguration

SeataDataSourceAutoConfiguration 主要是配置数据源代理,可以看到:

默认seata.enabled、seata.enableAutoDataSourceProxy、seata.enable-auto-data-source-proxy都是true只有当classpath中有DataSource时才会进行此配置创建了一个SeataAutoDataSourceProxyCreator,用于自动代理数据源

先记一下,SeataAutoDataSourceProxyCreator是一个BeanPostProcessor

刚才new了一个SeataAutoDataSourceProxyCreator,继续看构造方法,默认useJdkProxy是false,excludes为空,dataSourceProxyMode是AT

构造方法中最重要的一件事情是构造AOP通知(拦截器),这里new了一个SeataAutoDataSourceProxyAdvice

SeataAutoDataSourceProxyAdvice是一个MethodInterceptor。

MethodInterceptor是aop中的一个接口,当目标方法被调用时就会调用与之关联的MethodInterceptor的invoke方法

至此,在构造方法中完成了advisors的赋值,advisors[]中有一个DefaultIntroductionAdvisor,DefaultIntroductionAdvisor中引用了SeataAutoDataSourceProxyAdvice

前面说过,SeataAutoDataSourceProxyCreator是一个BeanPostProcessor,而BeanPostProcessor是BeanFactory中的一个钩子(回调),称之为后置处理器

AbstractAutoProxyCreator#postProcessBeforeInstantiation()

AbstractAutoProxyCreator#postProcessAfterInitialization()

AbstractAutoProxyCreator#wrapIfNecessary()

AbstractAutoProxyCreator#getAdvicesAndAdvisorsForBean()

SeataAutoDataSourceProxyCreator#getAdvicesAndAdvisorsForBean()

SeataAutoDataSourceProxyCreator#wrapIfNecessary()

DataSourceProxyHolder维护了数据源对象与数据源代理对象的映射

至此,数据源代理部分就看完了,下面总结一下:

1、启动的时候自动配置数据源代理,创建了一个SeataAutoDataSourceProxyCreator

2、SeataAutoDataSourceProxyCreator在构造方法中创建AOP通知,并赋值给其属性

3、AbstractAutoProxyCreator是一个抽象类不能被实例化,能实例化的只有SeataAutoDataSourceProxyCreator

4、SeataAutoDataSourceProxyCreator从AbstractAutoProxyCreator那里继承了很多属性和方法,其中就包括postProcessBeforeInstantiation()、postProcessAfterInitialization()、createProxy()等等

5、SeataAutoDataSourceProxyCreator间接实现了BeanPostProcessor接口,也就是说它也是BeanPostProcessor的一个实现类

6、BeanFactory回调所有的BeanPostProcessor#postProcessAfterInitialization()时,就会调用SeataAutoDataSourceProxyCreator的postProcessAfterInitialization()方法,最终会调用wrapIfNecessary()方法

7、wrapIfNecessary()只关心DataSource对象,它负责为DataSource对象生成代理对象,并且在SeataAutoDataSourceProxyCreator中维护了DataSource对象与SeataDataSourceProxy对象之间的映射关心

8、创建代理对象时,会给DataSource对象应用AOP拦截器。用AOP的话来讲,就是给目标对象DataSource织入通知,并创建一个被增强的代理对象

9、通知(拦截器)是SeataAutoDataSourceProxyAdvice,它实现了MethodInterceptor接口

10、SeataAutoDataSourceProxyAdvice#invoke()方法所做的事情就是,拿到原始DataSource的代理对象,并且在代理对象上调用目标方法

综上所述,以上做的所有工作都是为了将来调用 javax.sql.DataSource 上的任意方法时都会被拦截,然后调用其代理对象上对应的方法。而DataSource中最重要的一个方法就是getConnection()

划重点:将来,所有调用 javax.sql.DataSource#getConnection() 都会被拦截,然后在代理对象上执行getConnection(),因此可以这样说

调 javax.sql.DataSource#getConnection() 实际上执行的是 io.seata.rm.datasource.SeataDataSourceProxy#getConnection()

2. SeataAutoConfiguration

SeataAutoConfiguration里面主要是配置GlobalTransactionScanner(全局事务扫描器)

seata.enabled=true 才会开启 SeataAutoConfiguration

GlobalTransactionScanner 也继承自 AbstractAutoProxyCreator,同时还实现了InitializingBean接口。BeanFactory在设置了所有bean属性之后会调用InitializingBean的afterPropertiesSet()方法

GlobalTransactionScanner#afterPropertiesSet()

io.seata.common.DefaultValues中定义了很多默认值

同样地,因为实现了BeanPostProcessor接口,所以在启动时BeanFactory实例化Bean之后,会调用GlobalTransactionScanner的postProcessAfterInitialization(),尽管这个postProcessAfterInitialization()方法时从AbstractAutoProxyCreator那里继承来的,但是不影响啊,还是会调用GlobalTransactionScanner这个bean的postProcessAfterInitialization()方法。于是,最终又会调wrapIfNecessary()方法。

GlobalTransactionScanner#wrapIfNecessary()

这里面有一个很重要的逻辑就是,创建了一个GlobalTransactionalInterceptor对象,并赋值给interceptor

AbstractAutoProxyCreator#getAdvicesAndAdvisorsForBean()是一个抽象方法,实现在子类GlobalTransactionScanner中

因此,所有在GlobalTransactionScanner#wrapIfNecessary()中被代理的对象,都被应用GlobalTransactionalInterceptor

GlobalTransactionalInterceptor也是一个MethodInterceptor

也就是说,目标方法的调用都会转到GlobalTransactionalInterceptor#invoke()上

GlobalTransactionalInterceptor#handleGlobalTransaction()

事务执行直接调用TransactionalTemplate的execute()方法

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

io.seata.tm.api.GlobalTransactionContext#getCurrent() 获取当前事务

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

Seata 1.5.2 源码学习(seata1.3.0配置)

tx是DefaultGlobalTransaction

io.seata.tm.api.DefaultGlobalTransaction#begin()

DefaultGlobalTransaction中的TransactionManager是DefaultTransactionManager

DefaultTransactionManager中提供了事务相关的底层操作

io.seata.tm.api.DefaultGlobalTransaction#commit()

io.seata.tm.api.DefaultGlobalTransaction#rollback()的逻辑与commit()类似,都是重试调用transactionManager.rollback(xid)

全局事务扫描器部分的代码就看到这里,下面总结一下:

1、配置项seata.enabled=true 会触发 SeataAutoConfiguration 自动配置

2、SeataAutoConfiguration中创建了一个GlobalTransactionScanner

3、GlobalTransactionScanner继承了AbstractAutoProxyCreator,并实现InitializingBean接口

4、初始化TM、RM

5、由于继承了AbstractAutoProxyCreator,所以BeanFactory会调用GlobalTransactionScanner#方法postProcessAfterInitialization(),最终会调用GlobalTransactionScanner#wrapIfNecessary()来为目标对象创建代理对象

6、GlobalTransactionScanner#wrapIfNecessary()中创建了一个GlobalTransactionalInterceptor,GlobalTransactionalInterceptor是一个MethodInterceptor

7、在创建代理对象的时候,在AbstractAutoProxyCreator#wrapIfNecessary()方法中,为代理对象应用GlobalTransactionalInterceptor,于是所有目标对象上的方法调用就会转为调用GlobalTransactionalInterceptor#invoke()

8、GlobalTransactionalInterceptor#invoke()方法中,首先获取被调用的目标对象的Class和Method对象,然后检查目标方法或类上是否有@GlobalTransactional或@GlobalLock注解,而且配置项中不能禁用全局事务

9、如果加了@GlobalTransactional注解,则创建一个AspectTransactional,然后开始处理全局事务,默认传播特性是REQUIRED

10、如果加了@GlobalLock注解,则开始处理全局锁

11、处理全局事务就是直接调用事务模板中的execute方法,TransactionalTemplate#execute()是一个模板方法,其中定义了事务处理的流程。首先开启事务,然后执行业务逻辑,最后提交事务,异常回滚事务。

12、事务操作是在DefaultGlobalTransaction中处理的,最终处理在DefaultTransactionManager。DefaultTransactionManager负责同步远程调用,向TC发请求来开启、提交、回滚事务等操作

3. 数据库操作执行SQL语句

通过Java自带的JDBC操作数据库通常是这样的:

Class.forName(driverClass);// 获取ConnectionConnection connection = DriverManager.getConnection(url,user,password);// 创建Statement或者PreparedStatementStatement stmt = connection.createStatement();stmt.execute(sql);// PreparedStatement ps = connection.prepareStatement(sql);// ps.execute();

MyBatis底层也是这一套

接下来看Seata是如何做的

首先是获取数据库连接Connection,前面已经说过了,调用DataSource的getConnection()方法底层是在代理对象SeataDataSourceProxy上调用getConnection()。SeataDataSourceProxy是接口,如果是AT模式,则这个数据源代理对象是DataSourceProxy

DataSourceProxy#getConnection()获取数据库连接

ConnectionProxy#createStatement()

ConnectionProxy#prepareStatement()

PreparedStatementProxy 继承自 StatementProxy,因此下面就直接看PreparedStatementProxy如何执行SQL

PreparedStatementProxy#execute()

ExecuteTemplate#execute() 是一个模板方法

挑一个看看吧,就挑UpdateExecutor

UpdateExecutor构造方法中一直调父类的构造法,既然如此,那么直接看BaseTransactionalExecutor

UpdateExecutor#execute()

这个方法时从BaseTransactionalExecutor那里继承来的,又是一个模板方法,可见设计模式是多么重要

AbstractDMLBaseExecutor#doExecute()

AbstractDMLBaseExecutor#executeAutoCommitTrue()

ConnectionProxy#changeAutoCommit()

现在事务自动提交已经被Seata改成false了

UpdateExecutor#beforeImage()

BaseTransactionalExecutor#prepareUndoLog()

接下来,提交事务

ConnectionProxy#commit()

ConnectionProxy#processGlobalTransactionCommit() 处理全局事务提交

分支事务提交以后,业务数据更改和undo_log就都提交了

回想一下,为什么在执行业务修改前要先将默认的自动提交改成手动提交,最后再改成自动提交呢?

因为,要将业务数据修改和插入undo_log放在同一个事务里,一起提交

这一切都归功于代理

回顾一下整个调用链

结合之前的案例,AT模式TC、TM、RM三者的交互应该是这样的:

问题一:为什么在执行的时候,先将数据库自动提交autoCommit设为false,最后再改成true呢?

答:因为,需要将undo_log和业务数据修改放到同一个事务中,这样可以保证业务数据修改成功后undo_log必然插入成功,所以Seata要将其改为手动提交。最后再改成true是因为默认autoCommit就是true,这样可以不影响其它业务。

问题二:什么情况下ConnectionContext中xid=null,且isGlobalLockRequire=true呢?或者换一种问法,什么情况下不在全局事务中,当仍然需要全局锁呢?

答:当业务方法上不加@GlobalTransactional,而是只加了@GlobalLock注解的情况下,就会出现上述情况,也就会执行 ConnectionProxy#processLocalCommitWithGlobalLocks()方法,在事务提交前检查全局锁,这样设计的目的是在AT模式下,不出现脏读、脏写。由于数据源被代理了,当一个加了@GlobalTransactional的全局事务,与另一个加了@GlobalTransactional或@GlobalLock注解的事务在本地事务提交前就会检查全局锁,要先获得全局锁才能提交本地事务,这样就避免了脏读脏写,从而相当于实现了全局事务的读已提交隔离级别。参见:https://seata.io/zh-cn/blog/seata-at-lock.html

关于Seata 1.5.2 Client端的源码学习就先到这里,欢迎交流~

如果你都已经看到了这里,不妨给我点个赞吧?

本文链接地址:https://www.jiuchutong.com/zhishi/310940.html 转载请保留说明!

上一篇:帝国CMS报错Table ‘empirecms.phome_ecms_’ doesn’t exist怎么解决(帝国cms8.0)

下一篇:帝国CMS灵动标签e:loop怎么用(帝国cms灵动标签 PHP变量文章ID加减1)

  • 华为matepadpro夜间自动断网怎么回事(华为matepadpro待机)

    华为matepadpro夜间自动断网怎么回事(华为matepadpro待机)

  • 抖音怎么设置作品点赞信息互关朋友可见(抖音怎么设置作品公开所有人可见)

    抖音怎么设置作品点赞信息互关朋友可见(抖音怎么设置作品公开所有人可见)

  • 红米k40有潜望镜头吗(红米k40有潜望镜功能吗)

    红米k40有潜望镜头吗(红米k40有潜望镜功能吗)

  • 三星a60听筒声音小(三星a60听筒声音很小)

    三星a60听筒声音小(三星a60听筒声音很小)

  • 小米9烧屏免费换吗(小米9烧屏免费修理)

    小米9烧屏免费换吗(小米9烧屏免费修理)

  • 抖音货到付款怎么取消订单(抖音货到付款怎么付钱)

    抖音货到付款怎么取消订单(抖音货到付款怎么付钱)

  • ps源文件是什么(ps源文件是什么意思)

    ps源文件是什么(ps源文件是什么意思)

  • 电子邮件地址怎么写苹果(电子邮件地址怎么弄?)

    电子邮件地址怎么写苹果(电子邮件地址怎么弄?)

  • se2是高通基带吗(se2用的啥基带)

    se2是高通基带吗(se2用的啥基带)

  • 苹果ID无效或不支持怎么办(苹果id无效或不受支持怎么办)

    苹果ID无效或不支持怎么办(苹果id无效或不受支持怎么办)

  • 散热器的作用(散热器的作用是使发动机冷却水强制循环)

    散热器的作用(散热器的作用是使发动机冷却水强制循环)

  • vlookup精确匹配是0还是1(vlookup精确匹配公式)

    vlookup精确匹配是0还是1(vlookup精确匹配公式)

  • lte版可以打电话吗(lte网络不能打电话)

    lte版可以打电话吗(lte网络不能打电话)

  • 小米手机亮度调到最低还是亮怎么办(小米手机亮度调节失灵)

    小米手机亮度调到最低还是亮怎么办(小米手机亮度调节失灵)

  • 麒麟810是什么水平处理器(麒麟810算什么级别的)

    麒麟810是什么水平处理器(麒麟810算什么级别的)

  • 华为充电器能充switch么(华为充电器能充电脑吗)

    华为充电器能充switch么(华为充电器能充电脑吗)

  • 爱奇艺会员安卓苹果互通吗(爱奇艺会员安卓和苹果互通吗)

    爱奇艺会员安卓苹果互通吗(爱奇艺会员安卓和苹果互通吗)

  • 手机可以测分贝吗(手机测声音分贝软件哪个好)

    手机可以测分贝吗(手机测声音分贝软件哪个好)

  • smg9350是什么手机

    smg9350是什么手机

  • 如何快速添加手机联系人(如何快速添加手机号到通讯录)

    如何快速添加手机联系人(如何快速添加手机号到通讯录)

  • p30pro充电会自动断电吗(华为p30pro充电一会自动断开)

    p30pro充电会自动断电吗(华为p30pro充电一会自动断开)

  • 淘宝抢购提醒在哪里看(淘宝抢购提醒在哪里)

    淘宝抢购提醒在哪里看(淘宝抢购提醒在哪里)

  • 苹果8p怎么装两个微信(苹果8p怎么装两个微信号)

    苹果8p怎么装两个微信(苹果8p怎么装两个微信号)

  • 苹果手机突然变暗了怎么回事(苹果手机突然变暗了怎么调到正常)

    苹果手机突然变暗了怎么回事(苹果手机突然变暗了怎么调到正常)

  • qq发送失败红色叹号(qq发送失败红色叹号多久出现)

    qq发送失败红色叹号(qq发送失败红色叹号多久出现)

  • 无线反向充电什么意思(无线反向充电什么手机支持)

    无线反向充电什么意思(无线反向充电什么手机支持)

  • 菜鸟驿站如何加盟(菜鸟驿站如何加盟条件)

    菜鸟驿站如何加盟(菜鸟驿站如何加盟条件)

  • 税控盘280怎么变398了
  • 什么是差额税金
  • 小规模纳税人外账处理
  • 一般纳税人的税务筹划
  • 非同一控制下企业合并对价小于可辨认
  • 划转税务的非税收入2023
  • 公司交的物业费入什么科目
  • 抵扣红冲发票怎么报税
  • 小规模纳税人取得的专票转为一般纳税人之后能抵扣吗
  • 存货盘亏进项税额转出会计分录
  • 固定资产税前一次性扣除政策中的扣除十点
  • 子公司注销是利空吗
  • 出口退税进项抵扣了不退税可以吗
  • 商业保险可以税前扣除多少
  • 食用油从商业流入的原因
  • 公司为员工购买五险一金是什么意思
  • 对外投资的风险及对策
  • 土地契税及印花税缴纳规定
  • 房屋租赁税务局开票税点
  • 可全额扣除的公益性捐赠支出
  • windows10如何开热点
  • 在linux系统中 用来存放系统所需
  • kb4598481是什么
  • ghost打开
  • php __callstatic
  • 注销公司的处理方式
  • 其他综合收益的构成项目如何
  • es6 promise await
  • 深入浅出讲解傅里叶变换
  • 本期收入及免税收入怎么填
  • 利润表利息费用包括哪些科目
  • 长投转可供
  • 税务局手续费返还政策
  • 销售佣金 会计分录
  • 为什么要结转成本?
  • 增值税申报系统登录密码
  • 我们买得起一辆新车吗?英文
  • 标签显示内容怎么设置
  • 无偿划转股权涉税
  • 增值税发票抵扣联的作用
  • 资金账簿印花税减半政策
  • 收到质量赔款涉税处理
  • 下列项目的进项税额可以从销项税额中抵扣的是()
  • 社保怎么交最划算
  • 企业注销指的是哪些
  • 房地产企业成本核算方法
  • 应收账款贷方如何核算
  • 研发支出是什么性质的科目
  • 冲暂估费用
  • 认缴制下实收资本可以减少吗
  • 结转已到期未兑现的商业承兑汇票会计分录
  • 代金券消费怎么入账
  • 工厂没给工人买社保我们应该找哪个部门
  • 公司购买一台电脑,会计科目怎么办
  • 财务费用利息收入怎么记账
  • 员工垫付的费用怎样记账
  • 生产车间买的工具计入什么费用
  • 个人承担的个税会计分录
  • win7下mysql6.x出现中文乱码的完美解决方法
  • mysql文件存储路径设置
  • MySQL-group-replication 配置步骤(推荐)
  • bios怎么恢复出厂设置有什么后果?
  • windows系统钥匙盘制作及启动密码的设置
  • win10系统资源
  • intel的me
  • centos init
  • windows8.1怎么升级
  • win10链接手机怎么用
  • Win10打不开IE浏览器
  • linux yw命令
  • win7旗舰版怎么连接无线网络
  • opengl做简单的模型
  • KBEngine v0.4.0 发布,分布式游戏服务端引擎
  • async/await与promise(nodejs中的异步操作问题)
  • js 实现ajax
  • android network
  • jquery iframe src
  • 企业购房契税怎么入账
  • 慧算账财务公司简介
  • 土地增值税分期清算条件?
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设