安装前提:安装了JDK
下载地址:https://github.com/seata/seata/releases
我这里下载的是最新版seata-server-1.4.1.tar.gz
DROP DATABASE IF EXISTS seata;
CREATE DATABASE seata DEFAULT CHARACTER SET utf8;
DROP TABLE IF EXISTS seata.global_table;
CREATE TABLE seata.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 = InnoDB DEFAULT CHARSET = utf8;
DROP TABLE IF EXISTS seata.branch_table;
CREATE TABLE seata.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 = utf8;
DROP TABLE IF EXISTS seata.lock_table;
CREATE TABLE seata.lock_table
(
`row_key` VARCHAR(128) NOT NULL,
`xid` VARCHAR(96),
`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 = InnoDB DEFAULT CHARSET = utf8;
修改使用 db 数据库,实现 Seata TC Server 的全局事务会话信息的共享
service {
vgroupMapping.multi-datasource-service-group = "default"
}
## transaction log store, only used in seata-server
store {
## store mode: file、db、redis
mode = "db"
## database store property
db {
## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
datasource = "dbcp"
## mysql/oracle/postgresql/h2/oceanbase etc.
dbType = "mysql"
driverClassName = "com.mysql.cj.jdbc.Driver"
url = "jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false"
user = "root"
password = "123456"
minConn = 5
maxConn = 100
globalTable = "global_table"
branchTable = "branch_table"
lockTable = "lock_table"
queryLimit = 100
maxWait = 5000
}
}
设置使用 Nacos 注册中心
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
loadBalance = "RandomLoadBalance"
loadBalanceVirtualNodes = 10
nacos {
application = "seata-server"
serverAddr = "192.168.199.112:8848"
group = "seata_demo"
namespace = "d197f572-96bf-400f-b21e-0f38a2198ef1"
cluster = "default"
username = "nacos"
password = "nacos"
}
file {
name = "file.conf"
}
}
config {
# file、nacos 、apollo、zk、consul、etcd3
type = "nacos"
nacos {
serverAddr = "192.168.199.112:8848"
namespace = "d197f572-96bf-400f-b21e-0f38a2198ef1"
group = "seata_demo"
username = "nacos"
password = "nacos"
}
file {
name = "file.conf"
}
}
Seata 官方提供了将配置信息(file.conf)批量导入到各种主流配置中心的 Shell 脚本,存放路径是在 Seata源码目录 script/config-center 目录
其中 config.txt 为通用参数文件,包含了 Seata Server(TC)需要的所有配置信息,需要根据实际情况更改文件里的以下内容
service.vgroupMapping.multi-datasource-service-group = "default"
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
store.db.user=root
store.db.password=123456
sh nacos-config.sh -h 127.0.0.1 -p 8848 -t d197f572-96bf-400f-b21e-0f38a2198ef1 -g seata_demo
启动第一个 TC Server 在后台
nohup sh bin/seata-server.sh -p 18091 -n 1 &
启动第二个 TC Server 在后台
nohup sh bin/seata-server.sh -p 28091 -n 2 &
代码地址
使用代码地址中,data.sql 脚本,创建 seata_order、seata_storage、seata_amount 三个库
然后启动项目,确保启动过程中没有任何报错信息,我遇到了如下错误,应该都是之前配置没对,得仔细检查
can not get cluster name in registry config 'service.vgroupMapping.multi-datasource-service-group', please make sure registry config correct
no available service 'null' found, please make sure registry config correct
目前数据库的数据情况
mysql> select * from seata_order.orders;
Empty set (0.00 sec)
mysql> select * from seata_product.product;
+----+-------+---------------------+
| id | stock | last_update_time |
+----+-------+---------------------+
| 1 | 10 | 2021-03-25 18:28:49 |
+----+-------+---------------------+
1 row in set (0.00 sec)
mysql> select * from seata_account.account;
+----+---------+---------------------+
| id | balance | last_update_time |
+----+---------+---------------------+
| 1 | 10 | 2021-03-25 18:28:49 |
+----+---------+---------------------+
1 row in set (0.00 sec)
创建订单接口
@Override
@DS(value = "order-ds")
@GlobalTransactional
public Integer createOrder(Long userId, Long productId, Integer price) throws Exception {
Integer amount = 1; // 购买数量,暂时设置为 1。
logger.info("[createOrder] 当前 XID: {}", RootContext.getXID());
// 扣减库存
productService.reduceStock(productId, amount);
// 扣减余额
accountService.reduceBalance(userId, price);
// 保存订单
OrderDO order = new OrderDO().setUserId(userId).setProductId(productId).setPayAmount(amount * price);
orderDao.saveOrder(order);
logger.info("[createOrder] 保存订单: {}", order.getId());
// 返回订单编号
return order.getId();
}
使用 Postman 模拟调用 http://127.0.0.1:8081/order/create 创建订单的接口
此时控制台日志,显示如下
使用 Postman 模拟调用 http://127.0.0.1:8081/order/create 创建订单的接口
控制台日志