SpringBoot整合seata实现分布式事务统一
Seata(Simple Extensible Autonomous Transaction Architecture)是一个简单可扩展的自治事务框架,由阿里巴巴于2019年开源。它提供了高性能和简单易用的分布式事务服务,支持多种事务模式,包括AT、TCC、SAGA和XA,以满足不同的业务场景需求。
原理说明
Seata实现事务回滚的原理主要基于两阶段提交协议(2PC),并结合了本地事务的ACID特性。以下是Seata事务回滚的关键步骤和原理:
-
全局事务的启动
服务调用Seata客户端发起全局事务,获取全局唯一的事务ID(XID)。这个XID在跨服务调用过程中通过上下文传播,使得各个微服务都能识别到同一全局事务。
-
分支事务注册
每个涉及分布式事务的服务在进行数据库操作前,会将其本地事务注册到TC(Transaction Coordinator),并与XID关联起来。
-
事务执行与数据暂存
在AT模式下,Seata通过代理数据库连接层,在本地事务执行过程中记录SQL操作前后的数据变化,保存为
Undo Log和Redo Log,以便后续回滚或重试。 -
第一阶段(准备阶段)
所有参与全局事务的分支事务首先尝试执行本地事务,并将准备提交的结果报告给TC。
-
第二阶段(提交或回滚阶段)
如果所有分支事务的第一阶段都成功,则TC通知所有RM(Resource Manager)进行全局提交,RM根据Undo Log和Redo Log完成最终提交。
若有任何分支事务失败,则TC通知所有RM进行全局回滚,RM利用Undo Log回滚已变更的数据。
一、 环境搭建
安装MySQL
用于存储Seata所需的数据表,如全局事务表、分支事务表等。
安装Seata Server
1. 拉取Seata Docker镜像
从Docker Hub拉取Seata的官方镜像。打开终端或命令行界面,执行以下命令:
docker pull seataio/seata-server:latest
下载最新的Seata Server镜像到你的本地Docker环境。
2. 运行Seata Server容器
拉取完镜像后,使用以下命令启动Seata Server容器:
docker run -d --name seata-server -p 8091:8091 seataio/seata-server:latest
3. 验证Seata Server是否运行
Seata Server启动后,你可以通过浏览器访问http://localhost:8091/来查看Seata Server的管理界面,默认用户名和密码是seata/seata。
4. 创建Docker Compose文件
如果使用Docker Compose管理的容器,docker-compose.yml内容如下:
version: '3'
services:
seata-server:
image: seataio/seata-server:latest
container_name: seata-server
ports:
- "8091:8091"
然后,通过以下命令启动Seata Server:
docker-compose up -d
。
二、代码工程配置
在项目的pom.xml文件中添加Seata的依赖,如下所示:
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.5</version> <!-- 使用Seata版本1.5 -->
</dependency>
在Spring Boot的配置文件中(如application.yml或application.properties),配置Seata的相关信息,包括服务组、事务服务组等。配置示例如下:
seata:
enabled: true
data-source-proxy-mode: AT
tx-service-group: group1
enable-auto-data-source-proxy: true
service:
vgroup-mapping:
group1: cluster1
grouplist:
cluster1: 127.0.0.1:8091
三、 服务接入
添加注解:在需要进行分布式事务管理的方法上添加@GlobalTransactional注解,这样Seata就会自动管理这些方法的事务,示例如下。
假设业务流程如下图所示
@Override
@GlobalTransactional
public Result createOrder(OrderDTO order) {
// 维护当前服务的订单
orderService.insert(order);
// 库存服务扣减库存
storageFeign.handleStock(order.getId(),order.getNum());
// 计费服务计算金额
Float money = calculateFeign.handleBill(order.getId(),order.getNum());
// 缴费服务扣减用户余额
Result result = payFeign.handlePay(order.getOperatorId(),money);
return result;
}
数据库配置:在数据库中初始化Seata所需的undo_log表,用于记录事务的回滚日志,sql如下。
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`branch_id` bigint(20) NOT NULL COMMENT '分支事务ID',
`xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '全局事务唯一标识',
`context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '上下文',
`rollback_info` longblob NOT NULL COMMENT '回滚信息',
`log_status` int(11) NOT NULL COMMENT '状态,0正常,1全局已完成(防悬挂)',
`log_created` datetime NOT NULL COMMENT '创建时间',
`log_modified` datetime NOT NULL COMMENT '修改时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'AT模式回滚日志表' ROW_FORMAT = DYNAMIC;
四、 配置Nacos
将Seata的配置文件上传到Nacos配置中心,以便Seata Server和各个微服务能够动态获取配置,示例如下。
service.vgroupMapping.group1=cluster1
#Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional.
store.mode=db
store.lock.mode=db
store.session.mode=db
#These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/order?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=123456
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=5000
确保nacos已经挂上seata服务后就可以开始进行测试使用了
五、 结语
虽然分布式事务在系统解耦方面能保持事务的一致性,但是在整合了seata这一类的事务统一中间件之后,不管中间件的性能多好,都会增加系统的复杂度和性能开销,在高并发的使用场景下尤为明显。
更多推荐
所有评论(0)