从1:1 ⇒ 1:N ⇒ N:N,开始出现分布式事务问题
分布式之后
单机应用被拆分成微服务应用,原来的三个模块被拆分成 三个独立的应用,分别使用 三个独立的数据源 ,业务操作需要调用 三个服务来完成。
此时 每个服务内部的数据一致性由 本地 事务来保证,但是 全局 的数据一致性问题没法保证。
一句话:一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用,就会产生分布式事务问题。
6.2 Seata简介官网
下载地址
是什么
Seata是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。
作用
一个典型的分布式事务过程:ID + 三组件模型
Transaction ID(XID):全局唯一的事务ID
三组件概念
Transaction Coordinator(TC):事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚
Transaction Manager(TM):控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议
Resource Manage(RM):控制分支(本地)事务,负责分支注册,状态汇报,并接受事务协调的指令,驱动分支(本地)事务的提交和回滚
处理过程(我们可以用这种方式帮助理解:RM-学生,TM-班主任,TC-授课老师)
TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID
XID在微服务调用链路的上下文中传播
RM向TC注册分支事务,将其纳入XID对应全局事务的管辖
TM向TC发起针对XID的全局提交或回滚决议
TC调度XID下管辖的全部分支事务完成提交或回滚请求
怎样用
本地 @Transational
全局 @GlobalTransational
seata的分布式交易解决方案
6.3 Seata-Server安装下载版本
修改conf目录下的file.conf配置文件
先备份原始file.conf文件
主要修改:自定义事务组名称 + 事务日志存储模式为db + 数据库连接
service模块 / store模块
mysql5.7数据库新建库seata,建表db_store.sql在seata-server-0.9.0\seata\conf目录里面
修改seata-server-0.9.0\seata\conf目录下的registry.conf目录下的registry.conf配置文件
目的是指明注册中心为nacos,及修改nacos连接信息。
先启动Nacos,端口号为8848
再启动seata-server:bin目录下seata-server.bat
6.4 订单/库存/账户业务数据库准备分布式事务业务说明
这里我们创建三个服务,一个订单服务,一个库存服务,一个账户服务。
当用户下单时,会在订单服务中创建一个订单,然后通过远程调用库存服务来扣减下单商品的库存,再通过远程调用账户服务来扣减用户账户里面的余额,最后在订单服务中修改订单状态为已完成。
该操作跨越三个数据库,有两次远程调用,很明显会有分布式事务问题。
创建业务数据库
建库sql
create database seata_order; create database seata_storage; create database seata_account;按照上诉3库分别建立对应业务表
# seata_order库下新建t_order表 DROP TABLE IF EXISTS `t_order`; CREATE TABLE `t_order` ( `int` bigint(11) NOT NULL AUTO_INCREMENT, `user_id` bigint(20) DEFAULT NULL COMMENT '用户id', `product_id` bigint(11) DEFAULT NULL COMMENT '产品id', `count` int(11) DEFAULT NULL COMMENT '数量', `money` decimal(11, 0) DEFAULT NULL COMMENT '金额', `status` int(1) DEFAULT NULL COMMENT '订单状态: 0:创建中 1:已完结', PRIMARY KEY (`int`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '订单表' ROW_FORMAT = Dynamic; # seata_storage库下新建t_storage表 DROP TABLE IF EXISTS `t_storage`; CREATE TABLE `t_storage` ( `id` bigint(11) NOT NULL AUTO_INCREMENT, `product_id` bigint(11) DEFAULT NULL COMMENT '产品id', `total` int(11) DEFAULT NULL COMMENT '总库存', `used` int(11) DEFAULT NULL COMMENT '已用库存', `residue` int(11) DEFAULT NULL COMMENT '剩余库存', PRIMARY KEY (`int`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '库存' ROW_FORMAT = Dynamic; INSERT INTO `t_storage` VALUES (1, 1, 100, 0, 100); # seata_account库下新建t_account表 CREATE TABLE `t_account` ( `id` bigint(11) NOT NULL COMMENT 'id', `user_id` bigint(11) DEFAULT NULL COMMENT '用户id', `total` decimal(10, 0) DEFAULT NULL COMMENT '总额度', `used` decimal(10, 0) DEFAULT NULL COMMENT '已用余额', `residue` decimal(10, 0) DEFAULT NULL COMMENT '剩余可用额度', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '账户表' ROW_FORMAT = Dynamic; INSERT INTO `t_account` VALUES (1, 1, 1000, 0, 1000);