注:启动server端多个实例
如图所示:新建一个maven项目新增Program arguments -p 端口号
1.file模式下启用seata配置
一.修改seata-server文件
- 首先是在seata官网下载seata相对应的服务端版本,注意服务端和客户端的版本冲突问题,具体可阅读官网。这里我采用的是server端是1.4.2(官方回复此版本有bug只可做为demo测试使用,建议升级至1.7.0最新版本.Nacos版本可不变动)
- 修改源码上的registry.conf文件。将registry和config的type修改为file.如下图展示
- 修改file文件
service {
# 事务组名称
vgroup_mapping.my-tx-group = "seata-server"
disableGlobalTransaction = false
}
如图展示:
4.根据seata-server源码上的脚本创建本地seata库。
二.client端配置
- 在resources目录下新建file.conf文件
service {
# 事务组名称
vgroup_mapping.my-tx-group = "seata-server"
#服务端server地址
default.grouplist="127.0.0.1:9091"
}
- 修改application.properties文件
# seata 配置
seata.application-id=demo
seata.enabled=true
seata.tx-service-group=my-tx-group
seata.service.grouplist.seata-server=127.0.0.1:9091
seata.service.vgroup-mapping.my-tx-group=seata-server
三.启动server端和client端检查控制台日志信息
服务端日志如下:
可以从server端看出RM和TM 都注册成功。
客户端日志如下:
连接到server端成功。至此file模式下启动分布式事务启动成功。但实际线上环境要保证数据持久化以及服务高可用一般采用db+nacos启用分布式事务。
2.Nacos+DB模式下启用seata配置
其他配置中心类似
一.下载并启动Nacos
- Nacos下载并修改为单机模式,win下进入bin下编辑startup.cmd。加入 set MODE=“standalone”,页面如下图所示。单机启动。根据需求可建立namespace空间。
二.配置seata-server为nacos方式启动
- 修改registry.conf 注册配置和配置中心配置为nacos方式,并配置对应的namespace地址,用户名密码,serverAddr和group如下图展示:
注意使用dataId指定服务端读取的配置文件,如图:
三.启动seata-server
启动后可在nacos控制台上看到服务端有注册到nacos且只有一个实例。
四.客户端配置
- 引入nacos依赖和seata依赖,注意我这里的springboot版本为2.0.1.RELEASE
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.4.2</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.4.2</version>
</dependency>
- yml文件配置如下:
spring:
datasource:
druid:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/db?serverTimezone=UTC
username: root
password: root
application:
name: springboot-seata-demo
server:
port: 80
#seata配置
seata:
#id必须要配置,否则会报错
application-id: springboot-seata
enabled: true
#配置中心
config:
type: nacos
nacos:
username: nacos
password: nacos
group: SEATA_GROUP
server-addr: localhost:8848
namespace: xxxxxxxxxxx
#读取nacos上的的配置文件(自己命名)
data-id: seata-client.properties
registry:
type: nacos
nacos:
application: seata-server
group: SEATA_GROUP
server-addr: localhost:8848
namespace: xxxxxxxxxxx
username: nacos
password: nacos
cluster: default
# seata 事务组编号 用于TC集群名
tx-service-group: seata_service_group
enable-auto-data-source-proxy: true
service:
# grouplist: 只会在file格式下起作用
# defalut: 127.0.0.1:9091
vgroupMapping:
seata_service_group: default
data-source-proxy-mode: AT
- seata-client.properties配置文件如下
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableClientBatchSendRequest=true
transport.threadFactory.bossThreadPrefix=NettyBossDigiwin
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
transport.threadFactory.bossThreadSize=1
transport.threadFactory.workerThreadSize=default
transport.shutdown.wait=3
transport.serialization=seata
transport.compressor=none
client.rm.asyncCommitBufferLimit=10000
client.rm.lock.retryInterval=10
client.rm.lock.retryTimes=30
client.rm.lock.retryPolicyBranchRollbackOnConflict=true
client.rm.reportRetryCount=5
client.rm.tableMetaCheckEnable=false
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.rm.tccActionInterceptorOrder=-2147482648
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
client.tm.interceptorOrder=-2147482648
client.undo.dataValidation=true
client.undo.logSerialization=jackson
client.undo.onlyCareUpdateColumns=true
client.undo.logTable=undo_log
client.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k
#此配置必须要有而且必须和本地配置文件一致
service.vgroupMapping.seata_service_group=default
service.enableDegrade=false
service.disableGlobalTransaction=false
- seataServer.properties 配置文档如下:
# 存储模式
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
# 需要根据mysql的版本调整driverClassName
# mysql8及以上版本对应的driver:com.mysql.cj.jdbc.Driver
# mysql8以下版本的driver:com.mysql.jdbc.Driver
store.db.driverClassName=com.mysql.jdbc.Driver
# 注意根据生产实际情况调整参数host和port
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true
# 数据库用户名
store.db.user=root
# 用户名密码
store.db.password=root
# 开启监控
metrics.enabled=true
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898
minConn=5
maxConn=100
globalTable="global_table"
branchTable="branch_table"
lockTable="lock_table"
queryLimit=100
maxWait=5000
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
server.distributedLockExpireTime=10000
五.启动客户端,同时检查nacos控制台,seata-server控制台日志以及客户端日志。成功如下图展示
nacos:
seata-server:
client:
五.解决 客户端订阅者的应用名为unknown
@Configuration
public class ProjectNameConfig implements EnvironmentAware {
@Value("${spring.application.name}")
private String applicationName;
@Override
public void setEnvironment(Environment environment) {
if(StringUtils.isBlank(System.getProperty("project.name"))){
System.setProperty("project.name",applicationName);
}
}
}
3.检验:同项目下多库验证seata功能
一. 引入dynamic依赖包,支持一个项目多个库的场景
<!-- dynamic-datasource-spring-boot-starter动态数据源 -->
<!-- 支持多数据源,,一个项目多个库的场景。 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
二. 本地mysql环境新增了三个库分别为:seata-order ,seata-account,seata-product。
三个库下分别存储了业务表外注意每个库下都必须要走undo_log表。
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NULL DEFAULT NULL,
`product_id` int(11) NULL DEFAULT NULL,
`pay_amount` int(11) NULL DEFAULT NULL,
`add_time` datetime NULL DEFAULT NULL,
`update_time` datetime NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 55 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for product
-- ----------------------------
DROP TABLE IF EXISTS `product`;
CREATE TABLE `product` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`price` int(11) NULL DEFAULT NULL,
`stock` int(11) NULL DEFAULT NULL,
`add_time` datetime NULL DEFAULT NULL,
`update_time` datetime NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of product
-- ----------------------------
INSERT INTO `product` VALUES (1, '电池', 10, 62, '2021-01-15 00:00:32', '2021-01-15 00:00:35');
-- ----------------------------
-- Table structure for account
-- ----------------------------
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NULL DEFAULT NULL,
`balance` int(11) NULL DEFAULT NULL,
`update_time` datetime NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of account
-- ----------------------------
INSERT INTO `account` VALUES (1, 1, 150, '2021-01-15 00:02:17');
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log` (
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
三. 配置多数据源
spring:
datasource:
dynamic:
seata: true
#必须要指定主数据源否则无法启动项目
primary: seata-orders
datasource:
#多数据源设置订单数据源
seata-orders:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: root
url: jdbc:mysql://127.0.0.1:3306/seata_orders?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false
#account 数据源配置
seata-account:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: root
url: jdbc:mysql://127.0.0.1:3306/seata_account?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false
#product 数据源配置
seata-product:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: root
url: jdbc:mysql://127.0.0.1:3306/seata_product?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false
四. 分别启动seata-sever和client项目即可找到对应的注册和连接成功日志。seata-server日志截图:
客户端截图:
五. 发起访问请求,如图所示:
debug:
当日志出现:Begin new global transaction [192.168.7.27:9091:7053067194827630891] 代表已经发起了一段全局事务的请求以及生成了贯穿全局的Xid(192.168.7.27:9091:7053067194827630891),日志如下
以及扣减库存和减余额的库的undo_log表中生成量两行分支id日志:
六. 修改seata默认超时时间
seata的默认超时时间为60000(1分钟)。为了方便演示我在debug上停留了1分钟以上,则会导致找不到xid,seata已经提前结束这段全局事务的行动。报错信息如下:
7. 建议将默认时间延长,我目前修改的时间为十分钟。修改seata-client.propertis(client.tm.defaultGlobalTransactionTimeout=600000)
数据正常回滚和流转。
4.启动seata-server两个实例,检查服务端稳定性。
- 启动两个实例,则可在nacos中看到注册有两个实例服务。
- 客户端发起请求,可看出访问的服务是随机模式。
访问到端口为9092的seata服务截图如下:
访问到端口为9092的seata服务截图如下: