博主随记分布式事务
前言
在springboot中存在事务的管理,在springcloud分布式事务中,由于各个模块的功能不同,在模块中会存在事务的嵌套。会因为事务的脏写问题、超时拥塞等各种原因出现各种各样的问题,而seata就是解决这些问题的框架。
一、seata事务管理的三个角色
- TC(Transaction Coordinator)-事务协调者:维护全局事务和分支事务的状态,协调全局事务提交或者回滚
- TM(Transaction Manager)-事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务
- RM(Resource Manager)-资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或者回滚
二、seata四种不同事务解决方案
- XA模式:强一致性分阶段事务模式,牺牲了一定的可用性,无业务入侵
- TCC模式:最终一致的分阶段事务模式,有业务入侵
- AT模式:最终一致的分阶段事务模式,无业务入侵,也是Seata的默认模式
- SAGA模式:长事务模式,有业务入侵
1.seata的XA模式
(1)工作流程
一阶段工作:
①RM(资源管理器)注册分支事务到TC(事务协调者)
②RM执行分支业务sql但不提交
③RM(资源管理器)报告执行状态到TC(事务协调者)
二阶段工作:
①TC(事务协调者)检测各个分支事务的执行状态
如果都成功:通知所有RM提交事务
如果有失败:通知所有RM回滚事务
三阶段工作:
接收TC(事务协调者)指令,提交或回滚事务
(2)XA模式的优点
事务的强一致性,满足ACID原则
常用数据库都支持,实现简单,无代码入侵
(3)XA模式的缺点
一阶段锁定数据库资源,等待二阶段才释放,性能较差
依赖关系型数据库实现事务
(4)XA模式的实现
1.引入依赖:
<!--seata依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <exclusions> <exclusion> <!--版本较低排除--> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> </exclusion> </exclusions> </dependency> <!--seata 1.42版本--> <dependency> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> <version>${seata.version}</version> </dependency> <!--参考官网的依赖配置--> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>1.4.2</version> </dependency>
2.修改application.yml文件(每个参与事务的微服务),开启XA模式
3.发起全局事务的入口方法添加@GlobalTransactional注解
4.重启项目测试,在项目的控制台可以查看日志输出,查看数据库数据是否回滚完整
2.seata的AT模式
(1)工作流程
AT同样是分阶段提交的事务模型,不过弥补了XA模型中资源锁定周期过长的缺陷
阶段一工作:
①RM注册分支事务
②记录undo-log(数据快照)
③执行业务sql并提交
④报告事务状态
二阶段工作:
①TC(事务协调者)检测各个分支事务的执行状态
可以提交:RM删除undo-log
不可以提交:RM根据undo-log回复数据到更新前
(2)AT模式的优点
- 一阶段完成直接提交事务,释放数据库资源,性能较好
- 利用全局锁实现读写的隔离
- 没有代码侵入,框架自动完成提交和回滚
(3)AT模式的缺点
两个阶段之间属于软状态,属于最终一致性
框架的快照性能会影响性能,但是比XA模式要好很多
(4)AT模式脏写问题及解决方案
(5)AT模式与XA模式的锁的区别:
数据库锁和tc的锁在粒度上是有差别的,XA数据库锁你任何人都无法访问这个数据,AT全局锁:操作这张表的全局事务由sesta管理,如果不是由seata管理的其他事务来操作数据库表的数据可以,所以在写隔离上才会存在一定的问题,AT模式为了解决这种问题,使用了两个快照before-image和after-image快照,来解决问题
(6)AT模式的实现
1.引入依赖(如上)
2.Lock_table导入到TC服务关联的数据库,undo_log表导入到微服务关联的数据库
/*
Navicat Premium Data TransferSource Server : local
Source Server Type : MySQL
Source Server Version : 50622
Source Host : localhost:3306
Source Schema : seata_demoTarget Server Type : MySQL
Target Server Version : 50622
File Encoding : 65001Date: 20/06/2021 12:39:03
*/SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for undo_log
-- ----------------------------
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log` (
`branch_id` bigint(20) NOT NULL COMMENT 'branch transaction id',
`xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'global transaction id',
`context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'undo_log context,such as serialization',
`rollback_info` longblob NOT NULL COMMENT 'rollback info',
`log_status` int(11) NOT NULL COMMENT '0:normal status,1:defense status',
`log_created` datetime(6) NOT NULL COMMENT 'create datetime',
`log_modified` datetime(6) NOT NULL COMMENT 'modify datetime',
UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'AT transaction mode undo table' ROW_FORMAT = Compact;-- ----------------------------
-- Records of undo_log
-- ------------------------------ ----------------------------
-- Table structure for lock_table
-- ----------------------------
DROP TABLE IF EXISTS `lock_table`;
CREATE TABLE `lock_table` (
`row_key` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`xid` varchar(96) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`transaction_id` bigint(20) NULL DEFAULT NULL,
`branch_id` bigint(20) NOT NULL,
`resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`table_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`pk` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`gmt_create` datetime NULL DEFAULT NULL,
`gmt_modified` datetime NULL DEFAULT NULL,
PRIMARY KEY (`row_key`) USING BTREE,
INDEX `idx_branch_id`(`branch_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
SET FOREIGN_KEY_CHECKS = 1;
3.配置application.yml文件开启AT模式(将XA改成AT)
4.重启服务并进行测试(相信大家都会)
3.seata的TCC模式
(1)TCC模式的优点
- 一阶段完成直接提交事务,释放数据库资源,性能好
- 相比AT模式,无需生成快照,无需使用全局锁,性能最强
- 不依赖数据库事务,依赖补偿操作,可用于非事务型数据库
由上图可以发现TCC模式原理还有一个优点就是不会出现脏写问题
(2)TCC模式的缺点
- 有代码入侵,需要人为编写try、Confirm、和Cancel接口,太麻烦
- 软状态,事务是最终一致性
- 要考虑Confirm和Cancel的失败情况,做好幂等处理
(3)TCC模式的实现
编写方法内容实现模式,在此需要注意的是TCC空回滚和业务悬挂
当某分支事务的try阶段阻塞时,可能导致全局事务超时而触发二阶段的cancel操作。在未执行try操作时先执行了cancel操作,这时cancel不能做回滚,就是空回滚。对于已经空回滚的业务,如果以后继续执行try,就永远不可能confirm或cancel,这就是业务悬挂。应当阻止执行空回滚后的try操作,避免悬挂(建议大家查找视频进行仔细理解)
seata的Sage模式:
(1)工作流程
Saga模式是SEATA提供的长事务解决方案,分为两个阶段
- 一阶段:直接提交本地事务
- 二阶段:成功则什么都不做;失败则通过编写补偿作业来回滚
(2)seata模式的优点
- 事务参与者可以基于事件驱动实现异步调用,吞吐高
- 一阶段直接提交事务,无锁,性能好
- 不用编写TCC中的三个阶段,实现简单
(3)seata模式的缺点
- 软状态持续时间不确定,时效性差
- 没有锁,没有事务隔离,会有脏写
(4)seata模式的实现
略,因为博主没有学习,所以在此省略。(*^▽^*)
总结
seata的了解到此结束,因为博主学习完视频,自己动手完,在写完文章得花费三到四个小时,真的是太累太累了,所以到此结束,最后祝大家元宵快乐(*^▽^*) (*^▽^*) (*^▽^*)