1、概念和历程
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
2、几种模式
2.1、术语
TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,驱动全局事务提交或回滚。
TM (Transaction Manager) - 事务管理器:定义全局事务的范围:开始全局事务、提交或回滚全局事务。
RM (Resource Manager) - 资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
2.2、AT 模式
前提:
- 基于支持本地 ACID 事务的关系型数据库。
- Java 应用,通过 JDBC 访问数据库。
整体机制:
- 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
二阶段:
- 提交异步化,非常快速地完成。
- 回滚通过一阶段的回滚日志进行反向补偿。
写隔离:
- 一阶段本地事务提交前,需要确保先拿到 全局锁 。
- 拿不到 全局锁 ,不能提交本地事务。
- 拿 全局锁 的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。
读隔离:
- 在数据库本地事务隔离级别 读已提交(Read Committed) 或以上的基础上,Seata(AT 模式)的默认全局隔离级别是 读未提交(Read Uncommitted) 。
- 如果应用在特定场景下,必需要求全局的 读已提交 ,目前 Seata 的方式是通过 SELECT FOR UPDATE 语句的代理。
工作机制:
- 一阶段--执行
- 二阶段--回滚
- 三阶段--提交
2.3、TCC 模式
回顾总览中的描述:一个分布式的全局事务,整体是 两阶段提交 的模型。全局事务是由若干分支事务组成的,分支事务要满足 两阶段提交 的模型要求,即需要每个分支事务都具备自己的:
- 一阶段 prepare 行为
- 二阶段 commit 或 rollback 行为
根据两阶段行为模式的不同,我们将分支事务划分为 Automatic (Branch) Transaction Mode 和 Manual (Branch) Transaction Mode。
AT 模式基于 支持本地 ACID 事务 的 关系型数据库:
- 一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
- 二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。
- 二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。
相应的,TCC 模式,不依赖于底层数据资源的事务支持:
- 一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
- 二阶段 commit 行为:调用 自定义 的 commit 逻辑。
- 二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。
所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中。
2.4、Saga 模式
Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。
适用场景:
- 业务流程长、业务流程多
- 参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口
优势:
- 一阶段提交本地事务,无锁,高性能
- 事件驱动架构,参与者可异步执行,高吞吐
- 补偿服务易于实现
缺点:
- 不保证隔离性(应对方案见用户文档)
3、集成 IDEA
3.1、部分效果
数据库设计,4个微服务,3个数据库
下单前,没有订单信息,商品数量为100,金额为1000
下单成功,有订单信息,商品数量-1,金额-100
下单异常,uodo_log表记录异常信息
异常全部回滚
3.2、配置文件
seata配置文件,把file.conf和registry.conf粘贴到resource目录下。由于项目配置使用的是nacos管理:
bootstrap.yml文件:
spring:
application:
name: seata-bussiness-service # 注册到nacos上的服务名
profiles:
active: dev
cloud:
nacos:
# 注册中心
discovery:
username: nacos
password: nacos
server-addr: localhost:8848 #Nacos地址
namespace: 6d2e2958-3e7b-448b-8107-87ab6b022ba9
# 配置中心
config:
username: nacos
password: nacos
server-addr: localhost:8848 #Nacos地址
file-extension: yml #指定文件后缀,默认properties
namespace: 6d2e2958-3e7b-448b-8107-87ab6b022ba9
# 治理中心
sentinel:
transport:
dashboard: http://localhost:9555 #配置sentinel dashboard地址
port: 8719
alibaba:
seata:
tx-service-group: my_test_tx_group
#feign:
# sentinel:
# enabled: true #打开sentinel对feign的支持
seata事务核心依赖:
<!--seata事务依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<!--druid数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
3.3、测试 demo
为了更加准确模拟异常和分布式环境,所以使用4个微服务,同时操作不同数据库,产生异常后全部回滚。
这4个服务,配置文件和pom依赖基本都一样,只是注册到nacos上的服务名不同罢了,举例一下的bussiness业务服务的结构图:
3.3.1 seata-account 账户服务
AccountController.java 控制层:
package com.llh.controller;
import com.llh.domain.Account;
import com.llh.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* User: lilinhan
* DateTime: 2023/12/15 15:03
*/
@RestController
@RequestMapping("/account")
public class AccountController {
@Autowired
AccountService accountService;
@RequestMapping("/deduct")
public String deduct(){
// 扣钱
Account account = accountService.getById(1);
if(account!=null && account.getMoney()>=100){
account.setMoney(account.getMoney()-100);
accountService.updateById(account);
}
return "扣除成功";
}
}
3.3.2 seata-order 订单服务
OrderController.java 控制层:
package com.llh.controller;
import com.llh.api.AccountFeign;
import com.llh.domain.Order;
import com.llh.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* User: lilinhan
* DateTime: 2023/12/15 14:54
*/
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
OrderService orderService;
@Autowired
AccountFeign accountFeign;
@RequestMapping("/porder")
public String porder(){
Order order = new Order();
order.setCount(1);
order.setCommodityCode("C1000");
order.setUserId("U1000");
order.setMoney(100);
// 1、下单
orderService.save(order);
//2、扣钱(RPC)
accountFeign.deduct();
return "下单成功";
}
}
AccountFeign.java 接口:
package com.llh.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* User: lilinhan
* DateTime: 2023/12/15 15:27
*/
@FeignClient(value = "seata-account-service",path = "account")
public interface AccountFeign {
@RequestMapping("/deduct")
public String deduct();
}
3.3.3 seata-storage 储存服务
StorageController.java 控制层:
package com.llh.controller;
import com.llh.domain.Storage;
import com.llh.service.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* User: lilinhan
* DateTime: 2023/12/15 14:46
*/
@RestController
@RequestMapping("/storage")
public class StorageController {
@Autowired
StorageService storageService;
@RequestMapping("/reduce")
// @GlobalTransactional(rollbackFor = Exception.class)//全局事务,有这个注解:TM
public String reduce(){
// 减库存
Storage storage = storageService.getById(1);
if(storage!=null && storage.getCount()>0){
storage.setCount(storage.getCount()-1);
storageService.updateById(storage);
}
return "扣减库存成功";
}
}
3.3.4 seata-bussiness 业务服务
BussinessController.java 控制层:
package com.llh.controller;
import com.llh.api.OrderFeign;
import com.llh.api.StorageFeign;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* User: lilinhan
* DateTime: 2023/12/15 15:52
*/
@RestController
@RequestMapping("/bussiness")
public class BussinessController {
@Autowired
OrderFeign orderFeign;
@Autowired
StorageFeign storageFeign;
@RequestMapping("/pay")
@GlobalTransactional(rollbackFor = Exception.class)//全局事务,有这个注解:TM
public String pay(){
storageFeign.reduce();
orderFeign.porder();
int i = 1/0;
return "支付成功";
}
}
OrderFeign.java 接口:
package com.llh.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* User: lilinhan
* DateTime: 2023/12/15 15:53
*/
@FeignClient(value = "seata-order-service",path = "order")
public interface OrderFeign {
@RequestMapping("/porder")
public String porder();
}
StorageFeign.java 接口:
package com.llh.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* User: lilinhan
* DateTime: 2023/12/15 15:53
*/
@FeignClient(value = "seata-storage-service",path = "storage")
public interface StorageFeign {
@RequestMapping("/reduce")
public String reduce();
}
3.3.5 uodo_log建表语句:
/*
Navicat Premium Data Transfer
Source Server : MySQL
Source Server Type : MySQL
Source Server Version : 80031 (8.0.31)
Source Host : localhost:3306
Source Schema : seata-storage
Target Server Type : MySQL
Target Server Version : 80031 (8.0.31)
File Encoding : 65001
Date: 16/12/2023 11:35:55
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for undo_log
-- ----------------------------
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log` (
`id` bigint NOT NULL AUTO_INCREMENT,
`branch_id` bigint NOT NULL,
`xid` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
`context` varchar(128) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `ux_undo_log`(`xid` ASC, `branch_id` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of undo_log
-- ----------------------------
SET FOREIGN_KEY_CHECKS = 1;
123 comments
2025年10月新盘 做第一批吃螃蟹的人coinsrore.com
新车新盘 嘎嘎稳 嘎嘎靠谱coinsrore.com
新车首发,新的一年,只带想赚米的人coinsrore.com
新盘 上车集合 留下 我要发发 立马进裙coinsrore.com
做了几十年的项目 我总结了最好的一个盘(纯干货)coinsrore.com
新车上路,只带前10个人coinsrore.com
新盘首开 新盘首开 征召客户!!!coinsrore.com
新项目准备上线,寻找志同道合 的合作伙伴coinsrore.com
新车即将上线 真正的项目,期待你的参与coinsrore.com
新盘新项目,不再等待,现在就是最佳上车机会!coinsrore.com
新盘新盘 这个月刚上新盘 新车第一个吃螃蟹!coinsrore.com
2025年10月新盘 做第一批吃螃蟹的人coinsrore.com
新车新盘 嘎嘎稳 嘎嘎靠谱coinsrore.com
新车首发,新的一年,只带想赚米的人coinsrore.com
新盘 上车集合 留下 我要发发 立马进裙coinsrore.com
做了几十年的项目 我总结了最好的一个盘(纯干货)coinsrore.com
新车上路,只带前10个人coinsrore.com
新盘首开 新盘首开 征召客户!!!coinsrore.com
新项目准备上线,寻找志同道合 的合作伙伴coinsrore.com
新车即将上线 真正的项目,期待你的参与coinsrore.com
新盘新项目,不再等待,现在就是最佳上车机会!coinsrore.com
新盘新盘 这个月刚上新盘 新车第一个吃螃蟹!coinsrore.com
2025年10月新盘 做第一批吃螃蟹的人coinsrore.com
新车新盘 嘎嘎稳 嘎嘎靠谱coinsrore.com
新车首发,新的一年,只带想赚米的人coinsrore.com
新盘 上车集合 留下 我要发发 立马进裙coinsrore.com
做了几十年的项目 我总结了最好的一个盘(纯干货)coinsrore.com
新车上路,只带前10个人coinsrore.com
新盘首开 新盘首开 征召客户!!!coinsrore.com
新项目准备上线,寻找志同道合 的合作伙伴coinsrore.com
新车即将上线 真正的项目,期待你的参与coinsrore.com
新盘新项目,不再等待,现在就是最佳上车机会!coinsrore.com
新盘新盘 这个月刚上新盘 新车第一个吃螃蟹!coinsrore.com
2025年10月新盘 做第一批吃螃蟹的人coinsrore.com
新车新盘 嘎嘎稳 嘎嘎靠谱coinsrore.com
新车首发,新的一年,只带想赚米的人coinsrore.com
新盘 上车集合 留下 我要发发 立马进裙coinsrore.com
做了几十年的项目 我总结了最好的一个盘(纯干货)coinsrore.com
新车上路,只带前10个人coinsrore.com
新盘首开 新盘首开 征召客户!!!coinsrore.com
新项目准备上线,寻找志同道合 的合作伙伴coinsrore.com
新车即将上线 真正的项目,期待你的参与coinsrore.com
新盘新项目,不再等待,现在就是最佳上车机会!coinsrore.com
新盘新盘 这个月刚上新盘 新车第一个吃螃蟹!coinsrore.com
2025年10月新盘 做第一批吃螃蟹的人coinsrore.com
新车新盘 嘎嘎稳 嘎嘎靠谱coinsrore.com
新车首发,新的一年,只带想赚米的人coinsrore.com
新盘 上车集合 留下 我要发发 立马进裙coinsrore.com
做了几十年的项目 我总结了最好的一个盘(纯干货)coinsrore.com
新车上路,只带前10个人coinsrore.com
新盘首开 新盘首开 征召客户!!!coinsrore.com
新项目准备上线,寻找志同道合 的合作伙伴coinsrore.com
新车即将上线 真正的项目,期待你的参与coinsrore.com
新盘新项目,不再等待,现在就是最佳上车机会!coinsrore.com
新盘新盘 这个月刚上新盘 新车第一个吃螃蟹!coinsrore.com
新车即将上线 真正的项目,期待你的参与coinsrore.com
新车上路,只带前10个人coinsrore.com
新车上路,只带前10个人coinsrore.com
新车新盘 嘎嘎稳 嘎嘎靠谱
新盘首开 新盘首开 征召客户!!!
新盘新项目,不再等待,现在就是最佳上车机会!
新车新盘 嘎嘎稳 嘎嘎靠谱coinsrore.com
新项目准备上线,寻找志同道合的合作伙伴coinsrore.com
新项目准备上线,寻找志同道合的合作伙伴coinsrore.com
大冒险家
成为齐柏林飞艇
排球之花
逃离酒庄
暴风
伊兹波德普拉德