Seata官方网址https://seata.io/zh-cn/docs/overview/what-is-seata.html
首先对之前的图书借阅系统进行升级:
编写对应的服务接口。
用户1号借阅1号书,显示已被借阅
1号借2号书则成功
1.常用的分布式事务解决方案
2PC-存在的问题
3PC-存在的问题
https://github.com/seata/seata/releases/download/v1.4.2/seata-server-1.4.2.zip
https://github.com/seata/seata/archive/refs/heads/develop.zip
接着将各个服务作为Seata的客户端,只需导入依赖即可。其他服务同理
添加配置文件
给每个服务启动类添加注解@EnableAutoDataSourceProxy
。
配置完重启所有的服务,此时重启后所有服务都连接到seata,但是没有开启任何的分布式服务。 接着通过注解添加分布式服务,添加完重启borrow服务。
此时因为Seata会分析修改数据的sql,同时生成对应的反向回滚SQL,这个回滚记录会放在undo_log表中,因此要求每个client都要有一个对应的undo_log表,(即每个服务连接的数据库都需要创建这样一个表,这里因为三个服务都用的一个数据库,因此只在这个数据库中添加一个undo_log即可)。sql定义如下:
CREATE TABLE `undo_log`
(
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`branch_id` BIGINT(20) NOT NULL,
`xid` VARCHAR(100) NOT NULL,
`context` VARCHAR(128) NOT NULL,
`rollback_info` LONGBLOB NOT NULL,
`log_status` INT(11) NOT NULL,
`log_created` DATETIME NOT NULL,
`log_modified` DATETIME NOT NULL,
`ext` VARCHAR(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8;
创建完表重启三个服务,此时已配置完成。
然后重置以下表的数据,分别如下:
book表
借阅表
用户表
seata
然后进行访问借阅接口进行效果测试。
测试1:1号人第一次借1号书。结果:成功
测试2:1号人再次借1号书。结果:失败
此时seata会将该方法中的事务回滚,可以看到书籍数量没有减少
测试3:1号人借2号书一次。结果:成功
书籍数量减少
再次借阅则失败
书籍数量未减少
此时在同一事务内的XID是一样的。
先单独为Seata配置一个命名空间
先关闭nacos和所有服务。然后修改seata目录conf下的配置文件register.conf。
注册信息配置完之后,需要将配置文件放到Nacos中,让Nacos管理配置,就可以进行热更新,直接在nacos中修改。
配置完然后回车
然后可以在nacos看到对应的配置:
然后需要将对应的事务组应映射配置也添加上,Datald格式为service.vgroupMapping.事务组名称,比如我们使用默认的名称,值全部default即可。在nacos配置事务组。
然后将对应的事务组映射配置也添加上,DataId格式为 service.vgroupMapping.事务组名称。此处使用默认的名称,值全部default即可。
接着将book-service和borrow-service同样的形式在nacos上配置事务组,即上边紧挨的两张图。
将本地改为nacos服务端。
其他user-service和book-service同理。配置完启动seata和三个服务。
然后重置数据库进行nacos上的seata测试。
测试1:1号人借1号书。 结果:成功
书籍数量减少
生成借阅信息
再次测试 ,可以看到效果和file类型是一样的,1号人借1号书,结果:借阅失败,书籍数量未减少,不过现在的注册和配置都继承在nacos中了。
先将所有服务关闭。
同理进入编辑
改为db进行保存
然后修改数据库驱动、URL、用户名密码
修改url
修改用户名密码
操作数据库
创建用户并给权限
创建数据库表
CREATE TABLE IF NOT EXISTS `global_table`
(
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`status` TINYINT NOT NULL,
`application_id` VARCHAR(32),
`transaction_service_group` VARCHAR(32),
`transaction_name` VARCHAR(128),
`timeout` INT,
`begin_time` BIGINT,
`application_data` VARCHAR(2000),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`xid`),
KEY `idx_status_gmt_modified` (`status` , `gmt_modified`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
`branch_id` BIGINT NOT NULL,
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`resource_group_id` VARCHAR(32),
`resource_id` VARCHAR(256),
`branch_type` VARCHAR(8),
`status` TINYINT,
`client_id` VARCHAR(64),
`application_data` VARCHAR(2000),
`gmt_create` DATETIME(6),
`gmt_modified` DATETIME(6),
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
`row_key` VARCHAR(128) NOT NULL,
`xid` VARCHAR(128),
`transaction_id` BIGINT,
`branch_id` BIGINT NOT NULL,
`resource_id` VARCHAR(256),
`table_name` VARCHAR(32),
`pk` VARCHAR(36),
`status` TINYINT NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`),
KEY `idx_status` (`status`),
KEY `idx_branch_id` (`branch_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
CREATE TABLE IF NOT EXISTS `distributed_lock`
(
`lock_key` CHAR(20) NOT NULL,
`lock_value` VARCHAR(20) NOT NULL,
`expire` BIGINT,
primary key (`lock_key`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('HandleAllSession', ' ', 0);
然后重启seata,看到数据源绑定成功:
重启所有服务,重置数据库和之前的类似。
进行借阅信息,但是报错显示服务名称过长。
解决过长问题,修改数据库字段类型,然后保存。
再次进行借阅两次,第一次显示成功,第二次显示已被借阅,书籍数量未减少。
到此关于nacos模式下的Seata部署就完成了。
但此时若在高并发请求下,同一时间100个人借同一个书,但同一个书只有3本,可能不会正常的只借出3本书。