Seata1分布式事务,安装、数据准备
1.Seata术语
是什么
Seata是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。
官网:http://seata.io/zh-cn/
能干嘛
一个典型的分布式事务过程
分布式事务处理过程的一ID+三组件模型:
- Transaction ID XID 全局唯一的事务ID
- 三组件概念
- TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,驱动全局事务提交或回滚。
- TM (Transaction Manager) - 事务管理器:定义全局事务的范围:开始全局事务、提交或回滚全局事务。
- RM (Resource Manager) - 资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
处理过程:
- TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID;
- XID在微服务调用链路的上下文中传播;
- RM向TC注册分支事务,将其纳入XID对应全局事务的管辖;
- TM向TC发起针对XID的全局提交或回滚决议;
- TC调度XID下管辖的全部分支事务完成提交或回滚请求。
2.Seata-Server安装(https://www.jianshu.com/p/fda8f616ba22)
去哪下
发布说明: Releases · seata/seata (github.com)
怎么玩
本地Transactional
全局GlobalTransactional
SEATA 的分布式交易解决方案
我们只需要使用一个 @GlobalTransactional 注解在业务方法上:
Seata-Server安装 ( (25条消息) seata1.4.2环境搭建_u012586389的博客-CSDN博客_seata1.4.2 )
基于windows 单机版
注册中心:Nacos
配置中心:Nacos
- 下载地址:https://github.com/seata/seata/releases
这里需要下载seata的服务zip包和源码的zip包
- seata 服务端配置修改
conf 目录下 修改registry.conf文件
注册类型改为nacos,及nacos的相关配置。最好新建一个命名空间专门隔离seata的服务和配置
registry.conf需要修改的部分 :
registry {# file 、nacos 、eureka、redis、zk、consul、etcd3、sofatype = "nacos"nacos {application = "seata-server"serverAddr = "127.0.0.1:8848"group = "SEATA_GROUP"namespace = "ce9eb940-4ef2-4e35-8451-2a755b6e196e"cluster = "default"username = "nacos"password = "nacos"}}config {# file、nacos 、apollo、zk、consul、etcd3type = "nacos"nacos {serverAddr = "127.0.0.1:8848"namespace = "ce9eb940-4ef2-4e35-8451-2a755b6e196e"group = "SEATA_GROUP"username = "nacos"password = "nacos"dataId = "seataServer.properties"}}
file.conf 需要修改的部分 :
## transaction log store, only used in seata-serverstore {## store mode: file、db、redismode = "db"## rsa decryption public keypublicKey = ""## database store propertydb {## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.datasource = "druid"## datasource = "dbcp"## mysql/oracle/postgresql/h2/oceanbase etc.dbType = "mysql"## mysql 5.xx## driverClassName = "com.mysql.jdbc.Driver"## mysql 8.0driverClassName = "com.mysql.cj.jdbc.Driver"## if using mysql to store the data, recommend add rewriteBatchedStatements=true in jdbc connection param## url = "jdbc:mysql://127.0.0.1:3306/my-seata?rewriteBatchedStatements=true"url = "jdbc:mysql://127.0.0.1:3306/my-seata?useUnicode=true&characterEncoding=utf-8&useSSL=false&nullCatalogMeansCurrent=true&serverTimezone=Asia/Shanghai"user = "root"password = "root"minConn = 5maxConn = 100globalTable = "global_table"branchTable = "branch_table"lockTable = "lock_table"queryLimit = 100maxWait = 5000}}
需要注意mysql8的 driverClassName 和5.x版本写法略有区别
新建库seata,建表sql:
-- -------------------------------- The script used when storeMode is 'db' ---------------------------------- the table to store GlobalSession dataCREATE 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_gmt_modified_status` (`gmt_modified`, `status`),KEY `idx_transaction_id` (`transaction_id`)) ENGINE = InnoDBDEFAULT CHARSET = utf8;-- the table to store BranchSession dataCREATE 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 = InnoDBDEFAULT CHARSET = utf8;-- the table to store lock dataCREATE 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),`gmt_create` DATETIME,`gmt_modified` DATETIME,PRIMARY KEY (`row_key`),KEY `idx_branch_id` (`branch_id`)) ENGINE = InnoDBDEFAULT CHARSET = utf8;
先启动Nacos端口号8848 nacos\bin\startup.cmd
再启动E:\myServices\seata-server-1.4.2\seata\seata-server-1.4.2\bin\seata-server.bat
下载源码:E:\myServices\seata-1.4.2 Releases · seata/seata (github.com)
将config.txt配置放在安装seata-server的目录下,与bin目录同级
将nacos-config.shcopy下来的文件放在安装seata目录下的conf目录
修改config.txt中的部分配置
将seata的配置导入到nacos的配置中心
在conf目录下,使用git将seata的配置导入nacos配置中心,前提是电脑环境上安装了git
使用如下命令进行导入:
sh nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t 0af6e97b-a684-4647-b696-7c6d42aecce7 -u nacos -w nacos
参数详情:命令解析:-h -p 指定nacos的端口地址;-g 指定配置的分组,注意,是配置的分组;-t 指定命名空间id; -u -w指定nacos的用户名和密码,同样,这里开启了nacos注册和配置认证的才需要指定。
按回车等待配置导入成功.
出现如图信息,说明导入成功。也可用去Nacos配置中心查看
3.Seata业务数据库准备
以下演示都需要先启动Nacos后启动Seata,保证两个都OK。
分布式事务业务说明
这里我们会创建三个服务,一个订单服务,一个库存服务,一个账户服务。
当用户下单时,会在订单服务中创建一个订单, 然后通过远程调用库存服务来扣减下单商品的库存,再通过远程调用账户服务来扣减用户账户里面的余额,最后在订单服务中修改订单状态为已完成。
该操作跨越三个数据库,有两次远程调用,很明显会有分布式事务问题。
一言蔽之,下订单—>扣库存—>减账户(余额)。
创建业务数据库
- seata_ order:存储订单的数据库;
- seata_ storage:存储库存的数据库;
- seata_ account:存储账户信息的数据库。
建库SQL
CREATE DATABASE seata_order;CREATE DATABASE seata_storage;CREATE DATABASE seata_account;
按照上述3库分别建对应业务表
- seata_order库下建t_order表
`` CREATE TABLE t_order (idBIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,user_idBIGINT(11) DEFAULT NULL COMMENT '用户id',product_idBIGINT(11) DEFAULT NULL COMMENT '产品id',countINT(11) DEFAULT NULL COMMENT '数量',moneyDECIMAL(11,0) DEFAULT NULL COMMENT '金额',status` INT(1) DEFAULT NULL COMMENT ‘订单状态: 0:创建中; 1:已完结’ ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
SELECT * FROM t_order;
- seata_storage库下建t_storage表
CREATE TABLE t_storage (
id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
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 ‘剩余库存’
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO seata_storage.t_storage(id, product_id, total, used, residue)
VALUES (‘1’, ‘1’, ‘100’, ‘0’,’100’);
SELECT * FROM t_storage;
- seata_account库下建t_account表
CREATE TABLE t_account(
id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY 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 ‘0’ COMMENT ‘剩余可用额度’
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO seata_account.t_account(id, user_id, total, used, residue)
VALUES (‘1’, ‘1’, ‘1000’, ‘0’, ‘1000’);
SELECT * FROM t_account;
按照上述3库分别建对应的回滚日志表- 订单-库存-账户3个库下**都需要建各自的回滚日志表**- \seata-server-0.9.0\seata\conf目录下的db_ undo_ log.sql- 建表SQL
— the table to store seata xid data
— 0.7.0+ add context
— you must to init this sql for you business databese. the seata server not need it.
— 此脚本必须初始化在你当前的业务数据库中,用于AT 模式XID记录。与server端无关(注:业务数据库)
— 注意此处0.3.0+ 增加唯一索引 ux_undo_log
drop table undo_log;
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;
```
