当前位置: 首页 > news >正文

Seata 分布式事务 快速开始

一、场景分析

假设现在有这么两个微服务 order、product,order 通过 feign 调用 product。

1.1、表结构

CREATE DATABASE IF NOT EXISTS `oms`;CREATE TABLE `oms_order` (`order_id` int NOT NULL AUTO_INCREMENT COMMENT '订单ID',`product_id` int NOT NULL COMMENT '商品ID',`quantity` int NOT NULL COMMENT '总数量',PRIMARY KEY (`order_id`)
) COMMENT='订单表';CREATE DATABASE IF NOT EXISTS `pms`;CREATE TABLE `pms_product` (`product_id` int NOT NULL AUTO_INCREMENT COMMENT '商品ID',`stock` int NOT NULL COMMENT '商品库存',`product_name` varchar(50) NOT NULL COMMENT '商品名称',PRIMARY KEY (`product_id`)
) COMMENT='商品表';INSERT INTO `pms_product` (`product_id`, `stock`, `product_name`) 
VALUES (1, 100, 'HuaWei Mate60 Pro');

 1.2、本地事务

@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {private final ProductFeignService productFeignService;@Override@Transactional(rollbackFor = Exception.class)public Order createOrder() {// 1、扣减库存PmsDeductStockDto dto = new PmsDeductStockDto();dto.setNum(1);dto.setProductId(1);productFeignService.deductStock(dto);// 2、创建订单Order order = new Order();order.setQuantity(1);order.setProductId(1);this.baseMapper.insert(order);int i = 1/0;// 报错return order;}
}

OrderServiceImpl#createOrder 加上了 @Transactional 注解,它是一个 Spring AOP 事务方法。因为 / by zero 错误,事务回滚,oms 数据库并没有插入订单数据;但是 pms 却扣减库存成功了。

pms_product 的库存 stock 从 100 被扣减到 99。

数据出现不一致:没有订单,库存却凭空减少。

这种不同数据库,或者相同数据库但不同服务之间的事务操作,所造成的数据不一致现象,叫做分布式事务问题。

我们使用 Seata 看看怎么来解决这个问题 →→

二、角色

Seata 的三大角色:

TC (Transaction Coordinator) - 事务协调者​

维护全局和分支事务的状态,驱动全局事务提交或回滚。

TM (Transaction Manager) - 事务管理器​

定义全局事务的范围:开始全局事务、提交或回滚全局事务。

RM (Resource Manager) - 资源管理器​

管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

Seata分TC、TM和RM三个角色,TC(Server端)为单独服务端部署,TM和RM(Client端)由业务系统集成。

三、部署 Seata 服务端

3.1、版本选择

根据  Spring Cloud Alibaba 组件版本关系,到官网下载对应的 Seata 版本。

因为我的 Spring Cloud Alibaba 版本是 2021.0.5.0,所以下载 1.6.1.zip。

3.2、执行建表语句

创建数据库 seata:

CREATE DATABASE IF NOT EXISTS `seata`;

根据自己的数据库,执行下载包 seata\script\server\db 下脚本:

 

3.3、修改配置

  • 修改 application.yml

修改 seata\conf\application.yml 文件,添加配置中心与注册中心信息。

seata:config:# support: nacos, consul, apollo, zk, etcd3type: nacosnacos:server-addr: 127.0.0.1:8848group: SEATA_GROUPdata-id: seataServer.propertiesusername: nacospassword: nacosregistry:# support: nacos, eureka, redis, zk, consul, etcd3, sofatype: nacosnacos:application:  seata-serverserver-addr: 127.0.0.1:8848group: SEATA_GROUPcluster: defaultusername: nacospassword: nacos

Seata 作为分布式事务协调者,可以通过注册中心与微服务通讯。

存疑:

config.nacos.namespace 如果配置 public 会起不来,不知道其他人会不会。

  • 修改 config.txt

修改 seata\script\config-center\config.txt 文件,并将内容上传到 Nacos 配置中心 public 命名空间下,data-id 为 seataServer.properties。

#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.cj.jdbc.Driver
store.db.url=jdbc:mysql://192.168.40.111:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=123456

修改事务信息的存储方式为 db,并修改数据库连接方式。

注意 mysql 8.0 以上,使用 com.mysql.cj.jdbc.Driver 驱动。

 3.4、启动

运行 seata\bin\seata-server.bat

Nacos 服务列表有 seata-server 证明启动成功。

登录 http://localhost:7091/#/login 用户名密码 seata/seata

四、配置 Seata 客户端(AT 模式)

4.1、导入依赖

order、product 的 pom.xml 添加依赖:

<!-- seata -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

4.2、配置 application.yml

order、product 的 application.yml 添加配置:

seata:application-id: ${spring.application.name}tx-service-group: default_tx_groupregistry:type: nacosnacos:application: seata-serverserver-addr: 127.0.0.1:8848group: SEATA_GROUPusername: nacospassword: nacosconfig:type: nacosnacos:server-addr: 127.0.0.1:8848group: SEATA_GROUPdata-id: seataServer.propertiesusername: nacospassword: nacos
  • tx-service-group 

seata 服务分组,要与服务端配置 service.vgroupMapping 的后缀对应。

  • config.nacos.data-id

新版本的 seata 服务端、客户端配置可以共用同一套。

 4.3、创建 undo_log 表(仅AT模式)

order、product 数据库创建 undo_log:

-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `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(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 KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDBAUTO_INCREMENT = 1DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';

4.4、添加 @GlobalTransactional 注解

@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {private final ProductFeignService productFeignService;@Override// @Transactional(rollbackFor = Exception.class)@GlobalTransactional(name="createOrder",rollbackFor=Exception.class)public Order createOrder() {// 1、扣减库存PmsDeductStockDto dto = new PmsDeductStockDto();dto.setNum(1);dto.setProductId(1);productFeignService.deductStock(dto);// 2、创建订单Order order = new Order();order.setQuantity(1);order.setProductId(1);this.baseMapper.insert(order);int i = 1/0;return order;}
}

4.5、启动并测试

访问 localhost:8012/order/create

order-service 控制台报错:

product-service 回滚了事务:

数据库:

在文章开头从 100 减为 99 后,就没有再变化了。证明 Seata 是有效的。

相关文章:

  • Crawl4AI:打破数据孤岛,开启大语言模型的实时智能新时代
  • 597页PPT丨流程合集:流程梳理方法、流程现状分析,流程管理规范及应用,流程绩效的管理,流程实施与优化,流程责任人的角色认知等
  • Docker Compose常用命令
  • 公路路面病害检测
  • 数据结构:顺序表的实现
  • 使用 Spring Boot Admin 通过图形界面查看应用配置信息的完整配置详解,包含代码示例和注释,最后以表格总结关键配置
  • 使用 rebase 轻松管理主干分支
  • 描述城市出行需求模式的复杂网络视角:大规模起点-目的地需求网络的图论分析
  • 数据仓库ODS、DWD、DWS、ADS各层介绍
  • 关于创建UNIX/Linux daemon进程的笔记
  • 【漫话机器学习系列】217.监督式深度学习的核心法则(Supervised Deep Learning Rule Of Thumb)
  • Spark-Streaming简介和核心编程
  • 【盈达科技GEO优化】向量数据库:人工智能营销时代的核心引擎
  • 【信息安全工程师备考笔记】第二章 网络信息安全概述
  • 门控循环单元(GRU)
  • 基于机器学习的房租影响因素分析系统
  • 力扣面试150题--有效的括号和简化路径
  • STM32 中断系统深度剖析
  • 高并发抢券系统设计与落地实现详解
  • 滴滴-golang后端开发-企业事业部门-二面
  • 四川一国企“80后”掌门人为报领导“知遇之恩”,盲目决策致数亿损失
  • 从中央政治局会议看经济工作着力点:以高质量发展的确定性应对外部不确定性
  • 蚂蚁财富28亿港元要约收购耀才证券,筹谋香港券商牌照
  • 云南鲁甸县一河滩突然涨水致4死,有人在救人过程中遇难
  • 印媒称印巴在克什米尔控制线沿线发生小规模交火,巴方暂未回应
  • 人民论坛:是民生小事,也是融合大势