四大模式:AT,TCC,XA,SAGA
1. AT模式(Automatic Transaction)
- 核心机制:通过自动生成反向SQL日志实现事务回滚,无需业务代码侵入
- 缓存适用性:
- 适用于Redis等支持事务的缓存中间件
- 通过Undo Log记录数据快照,回滚时自动恢复缓存状态
- 优势:实现简单,性能较高(一阶段直接提交)
- 局限:强依赖数据库事务能力,非关系型缓存支持有限
2. TCC模式(Try-Confirm-Cancel)
- 核心机制:通过业务层实现的Try/Confirm/Cancel三阶段控制事务
- 缓存适用性:
- 适用于所有缓存类型(包括无事务支持的缓存)
- 需手动编写Try阶段预留资源、Confirm/Cancel阶段提交/释放的逻辑
- 优势:灵活性高,可跨异构存储(如DB+Redis组合)
- 局限:代码侵入性强,需处理幂等和空回滚问题
3. SAGA模式
- 核心机制:通过事件驱动的长事务流程,每个步骤需配套补偿操作
- 缓存适用性:
- 适合跨多服务的缓存一致性场景(如订单→库存→积分链式调用)
- 补偿逻辑需显式处理缓存回滚
- 优势:支持长时间运行的业务流程
- 局限:需保证补偿操作的幂等性,实现复杂度高
4. XA模式
- 核心机制:基于两阶段提交(2PC)的强一致性协议
- 缓存适用性:
- 仅适用于支持XA协议的缓存(如部分关系型数据库缓存)
- 资源锁定时间长,高并发场景性能差
- 优势:严格保证ACID特性
- 局限:不适用于Redis等主流缓存系统
思考: 阿里巴巴的Seata-AT模式如何做到对业务的无侵入?
一是通过@GlobalTransactional注解自动触发全局事务,业务代码无需感知分布式事务的存在;
二是框架在JDBC层拦截SQL,自动记录数据变更前后的快照,回滚时用这些快照生成逆向SQL,完全无需业务干预。对比其他模式,比如TCC需要自己写补偿逻辑,AT模式更适合对代码简洁性要求高的场景。这个可以说是seata-At的实现原理吗
两阶段自动化处理
- 一阶段提交:业务数据和Undo Log在同一本地事务中提交,释放本地锁和连接资源。
- 二阶段补偿:由Seata框架异步处理回滚逻辑,业务无感知
Seata安装
1、下载Seata安装包,并且解压到安装路径下
其中conf文件下的application.example.yml 是配置例子
2、在不改变任何配置文件下,在bin文件夹下就可以直接启动。这样就可以使用了,一下是启动指令,如果seata安装地址在本地可以不知道ip地址(省去 -h <ip地址> )
./seata-server.sh -h <ip地址> -port 8091
3、更改配置文件(bin/application.yml),使用nacos做配置中心和注册中心
4、到nacos添加相关配置文件,文件名保持和上图标注的一样,一下是配置的相关信息
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driverstore.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=!QAZxsw2
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000service.vgroupMapping.init-group=default
service.default.grouplist=127.0.0.1:8091
5、创建seata数据库,并创建以下表
CREATE TABLE `branch_table` (`branch_id` bigint NOT NULL,`xid` varchar(128) NOT NULL,`transaction_id` bigint DEFAULT NULL,`resource_group_id` varchar(32) DEFAULT NULL,`resource_id` varchar(256) DEFAULT NULL,`branch_type` varchar(8) DEFAULT NULL,`status` tinyint DEFAULT NULL,`client_id` varchar(64) DEFAULT NULL,`application_data` varchar(2000) DEFAULT NULL,`gmt_create` datetime(6) DEFAULT NULL,`gmt_modified` datetime(6) DEFAULT NULL,PRIMARY KEY (`branch_id`),KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;CREATE TABLE `distributed_lock` (`lock_key` char(20) NOT NULL,`lock_value` varchar(20) NOT NULL,`expire` bigint DEFAULT NULL,PRIMARY KEY (`lock_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;CREATE TABLE `global_table` (`xid` varchar(128) NOT NULL,`transaction_id` bigint DEFAULT NULL,`status` tinyint NOT NULL,`application_id` varchar(32) DEFAULT NULL,`transaction_service_group` varchar(32) DEFAULT NULL,`transaction_name` varchar(128) DEFAULT NULL,`timeout` int DEFAULT NULL,`begin_time` bigint DEFAULT NULL,`application_data` varchar(2000) DEFAULT NULL,`gmt_create` datetime DEFAULT NULL,`gmt_modified` datetime DEFAULT NULL,PRIMARY KEY (`xid`),KEY `idx_status_gmt_modified` (`status`,`gmt_modified`),KEY `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;CREATE TABLE `lock_table` (`row_key` varchar(128) NOT NULL,`xid` varchar(128) DEFAULT NULL,`transaction_id` bigint DEFAULT NULL,`branch_id` bigint NOT NULL,`resource_id` varchar(256) DEFAULT NULL,`table_name` varchar(32) DEFAULT NULL,`pk` varchar(36) DEFAULT NULL,`status` tinyint NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',`gmt_create` datetime DEFAULT NULL,`gmt_modified` datetime DEFAULT NULL,PRIMARY KEY (`row_key`),KEY `idx_status` (`status`),KEY `idx_branch_id` (`branch_id`),KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
6、到此安装配置成功,在bin文件夹下 执行启动指令 ./seata-server.sh -h <ip地址> -port 8091
整合到SpringCloud工程使用
1、在对应工程中添加依赖
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId></dependency>
2、添加配置
## seata注册中心,要和seata server的application.yml配置保持一致
seata.registry.type=nacos
seata.registry.nacos.application=seata-server
seata.registry.nacos.server-addr=http://127.0.0.1:8848
seata.registry.nacos.group=SEATA_GROUP
seata.registry.nacos.username=nacos
seata.registry.nacos.password=nacos
#
## seata配置中心,要和seata server的application.yml配置保持一致
seata.config.type=nacos
seata.config.nacos.server-addr=http:/127.0.0.1:8848
seata.config.nacos.group=SEATA_GROUP
seata.config.nacos.dataId=seataServer.properties
seata.config.nacos.username=nacos
seata.config.nacos.password=nacos# 事务组名称,必须在nacos中有配置过:service.vgroupMapping.init-group=default
seata.tx-service-group=init-group
3、需要在数据库中创建undo_log表(官方提供的)
CREATE TABLE `undo_log` (`branch_id` bigint NOT NULL COMMENT 'branch transaction id',`xid` varchar(128) NOT NULL COMMENT 'global transaction id',`context` varchar(128) NOT NULL COMMENT 'undo_log context,such as serialization',`rollback_info` longblob NOT NULL COMMENT 'rollback info',`log_status` int 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 KEY `ux_undo_log` (`xid`,`branch_id`),KEY `ix_log_created` (`log_created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='AT transaction mode undo table';
使用seata
@Override @GlobalTransactional //开启事务注解public void saveMember(MemberSaveReq req) {DateTime now = DateTime.now();Member member = BeanUtil.copyProperties(req, Member.class);if (ObjectUtil.isNull(member.getId())) {memberFeign.save(member);Double a= null;double ad= 1/a;member.setId(SnowUtil.getSnowflakeNextId());memberMapper.insert(member);} else {memberMapper.updateByPrimaryKey(member);}}