springcloud进阶:四种分布式事务模式之AT模式(一)

0.引言

之前我们讲解了分布式事务组件seata的快速入门,但是针对分布式事务本身的4种模式还没有详细的介绍,所以我们就针对于4种分布式事务模式详解,并且梳理一下他们的应用场景

1. AT模式 (自动事务Auto Transaction)

AT模式根据其名称也能反馈出来他的特性,他是自动型的分布式事务解决方案。这个自动提现在他无需代码入侵,也就是说我们不需要再编写多余的代码来实现这个模式,只需要在方法中添加上指定的注解即可。

那么AT模式是如何实现无代码入侵的呢?他的工作原理是什么?

1.1 AT模式原理总览

AT模式分成两阶段来工作,我们先省略部分细节来整体了解其过程:

  • 一阶段:
    (1)拦截并解析业务SQL,找到需要在数据表中更新的数据,将其转换为undo_log,并且保存到提前在每个数据库中创建的undo_log表中
    打个比方,如果你是在做update product set price = 20 where price=10 and id=1的操作
    那么undo_log中保存的就是反向sqlupdate product set price=10 where price=20 and id=1。当然它的存储不会直接这么存,会经过处理。
    (2)然后执行业务SQL,这时你会发现数据库中的数据是发生变化了的,同时undo_log中也有对应的新增数据
  • 二阶段
    (1)因为第一阶段已经提交了本地事务,数据已经更新过了,这个时候如果没有报错,那么直接删除掉undo_log以及行锁的数据即可
    (2)但是如果发生了报错,就只需要根据undo_log来回退数据
    在这里插入图片描述
    这个就是AT模式执行的两阶段的整体视角,我们可以体会到的是AT模式下,自动帮助我们生成了undo_log、一阶段、二阶段的提交都是由seata完成的,并不需要我们写代码来实现,所以它的无代码入侵体现在这里。

1.2 AT模式 本地事务与全局事务

但是我们还没有解释本地事务和全局事务之间的联系,接下来我们把多个服务引入进来,进行横向解析

讲解之前我们要明确几个角色,这几个角色不是在AT模式中独有,而是也适用于其他模式

  • TM: Transaction Manager 事务管理器
    全局事务的管理者,或者说是全局事务的发起方,再通俗一点就是标注了@GlobalTransactional的方法所在的服务
  • RM: Resources Manager 资源管理
    负责分支(本地)事务注册、提交和回滚。每个服务都是一个RM,负责本地事务的管理
  • TC:Transaction Coordinate 事务协调器
    全局事务的协调者,TM,RM启动的时候要向TC注册,TM创建的时候要向TC申请一个全局事务ID,所以整个事务的把控是在TC中的,但是各自事务的管理是在RM中

下面我们用一张图来表明各自的作用关系(这张图请大家静下心,跟着标识按序阅读下去你就会明白三个角色之间是如何合作的)
在这里插入图片描述
同时基于上图,我们也知道全局事务由TM发起,本地事务由各服务自己管理,本地事务和全局事务之间是通过TC来进行协调

1.3 AT模式 全局锁

那么我们再把锁的概念加入进来进一步理解

我们先假设一个场景:

  • 业务1和业务2同样需要对product表中的同一行数据进行修改
  • 业务1先执行,其中本地事务1执行的时候获取到product表的对应行锁
  • 这时业务2也开始执行,要更新product时发现锁已被人拿了,那么他就先等着
  • 当业务1的本地事务1执行完成并提交后,业务2拿到了行锁,这时他再去修改获取到的是业务1修改过后的数据,他再进行修改提交
  • 可这时业务1并没有执行完,它在执行本地事务2时发生了错误,要执行回滚,可就在这时发现,自己事务1中的数据被其他事务篡改过了,他再执行undo_log可能就无法再回滚了

这里想象下为什么不可以再回滚?

我们假设下如果业务1的本地事务1的操作是

update product price = 20 where price=30 and name=1;

那么事务1的undo_log就是

update product price=30 where price=20 and name=1;

而业务2的操作是

update product price=25 where name=1;

那么到业务2操作完,事务1进行回退时就出现问题了,它根本找不到一条price=20 and id=1的数据,也就导致无法回滚。从而出现了脏写
在这里插入图片描述

那么这个问题我们要如何解决呢?

解决办法就是加全局行锁

我们的全局事务开启后,会申请全局行锁,同时业务2也添加上全局行锁,如seata实际的处理就是在业务2方法上也添加注解@GlobalTransactional或者@GlobalLock

这样当业务2执行会发现全局行锁被获取了,就会一直等待锁释放。只有到业务1整体提交完成后,全局锁才会释放,这样也就避免了脏写的发生
在这里插入图片描述

1.4 AT模式完整流程

我们加入锁,同时也加入了before image和after image的概念,来完整的讲解整个流程

首先理解before image指的是本地事务未开始之前查询出来的原数据的快照。after image指本地事务执行完后生成的事务后数据快照。

通过before image可以反向生成回滚sql并保存到undo_log中

如果事务执行无报错那么就删除掉锁、undo_log、image等中间数据

如果事务执行有报错,那么先比较after image与当前数据库中的数据来判断是否发生了脏读/写,如果发生了说明中间有其他业务操作了这些数据,这时就将报错上报,由人工处理,而避免脏写可以通过如上述所说的在其他业务中添加上@GlobalTransactional或者@GlobalLock注解;如果没有脏读那就通过undo_log回退数据。
在这里插入图片描述
如上就是AT模式,核心是理解两阶段提交、本地事务和全局事务之间的关系、以及全局锁的引入

1.5 AT模式应用场景

AT模式是实际开发中最常用的模式,他无代码入侵的特性,适应于不希望对代码进行改造的场景,因为AT模式要求数据库是支持本地事务的数据库,但是因为市面上多数使用的都是支持事务的数据库,所以其应用也十分广泛

同时其性能也还不错,完全满足普通业务,如果对于性能有较高要求的,就要用到我们其他模式的,这个我们也在下一章进行讲解

AT应用场景总结:

  • 不希望对代码进行改造
  • 数据库支持事务操作
  • 对性能没有特别高的要求
  • 22
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
在Spring Cloud Alibaba中使用Seata进行分布式事务,需要进行以下配置: 1. 添加Seata相关依赖:在pom.xml文件中添加Seata的依赖。 2. 配置Seata Server地址:在application.properties或application.yml文件中配置Seata Server的地址,例如:spring.cloud.alibaba.seata.server-address=127.0.0.1:8091。 3. 配置数据源代理:在数据源的配置文件中添加Seata的代理数据源,例如: ``` spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.jdbc.Driver # Seata代理数据源 spring.cloud.alibaba.seata.tx-service-group=my_test_tx_group spring.cloud.alibaba.seata.datasource.autoproxy=true ``` 4. 配置Mybatis和Spring的集成:在Mybatis和Spring的配置文件中添加Seata的相关配置,例如: ``` <!-- Mybatis --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath*:com/test/mapper/*.xml"/> <property name="configLocation" value="classpath:mybatis-config.xml"/> </bean> <!-- Spring --> <bean id="transactionManager" class="io.seata.spring.annotation.GlobalTransactionScanner"> <constructor-arg name="txServiceGroup" value="my_test_tx_group" /> <property name="applicationId" value="test" /> <property name="zookeeper" value="localhost:2181" /> </bean> ``` 5. 添加Seata注解:在需要进行分布式事务的方法上添加@GlobalTransactional注解。 以上就是使用Spring Cloud Alibaba和Seata进行分布式事务的配置步骤。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wu@55555

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值