- 开启seata事务的工程中引入相关依赖
在父工程pom.xml中引入seata的jar包,如果使用1.4.2的版本,需要排除默认引入的1.3的包。
com.alibaba.cloud
spring-cloud-starter-alibaba-seata
io.seata
seata-spring-boot-starter
io.seata
seata-spring-boot-starter
${seata.version}
关于spring cloud alibaba生态的版本参考地址
如果使用1.3.0的版本则可以在子项目引入
io.seata
seata-spring-boot-starter
⚠️⚠️⚠️如果使用此依赖,将会出现 服务A->B,B报错,A事务回滚,但是B事务不会回滚,因为此依赖在请求传递中header不会携带xid。
建议直接使用
com.alibaba.cloud
spring-cloud-starter-alibaba-seata
2021.1
- seata server服务器搭建
github下载地址
下载1.3.0版本,本文以1.3.0版本为例。seata-server-1.3.0.tar.zip上传至服务器进行解压、配置。
-
- 修改seata/conf/file.conf文件
此配置项为seata 服务器的存储配置,存储方式选择db,再配置数据库的连接信息,以及处理事务的全局性表(表名使用默认的就可以)。
- 修改seata/conf/file.conf文件
store {
mode = "db"
db {
datasource = "druid"
dbType = "mysql"
driverClassName = "com.mysql.jdbc.Driver"
url = "jdbc:mysql://172.31.215.70:3306/seata"
user = "root"
password = "123456"
minConn = 5
maxConn = 30
globalTable = "global_table"
branchTable = "branch_table"
lockTable = "lock_table"
queryLimit = 100
maxWait = 5000
}
}
⚠️注意
driverClassName驱动的配置需要根据mysql的版本决定:
mysql5.+使用 driverClassName = "com.mysql.jdbc.Driver"
mysql8使用 driverClassName = "com.mysql.cj.jdbc.Driver"
-
- 修改seata/conf/registry.conf文件
需要配置选用的注册中心类型(nacos),注册中心的连接信息;配置中心的类型,配置中心的连接信息。
- 修改seata/conf/registry.conf文件
registry {
type = "nacos"
nacos {
application = "seata-server"
serverAddr = "172.31.215.72:8848"
group = "SEATA_GROUP"
namespace = "787964a5-e21d-4eb8-9999-9bcc9244bd48"
cluster = "default"
username = "nacos"
password = "nacos"
}
}
config {
type = "nacos"
nacos {
serverAddr = "172.31.215.72:8848"
namespace = "787964a5-e21d-4eb8-9999-9bcc9244bd48"
group = "SEATA_GROUP"
username = "nacos"
password = "nacos"
}
}
⚠️注意
namespace :生产环境和项目中保持一致
group: 和项目中保持一致
serverAddr: nacos连接地址,如果是内网,请保证服务器之前内网互通并打开端口防火墙
项目中的group如果不是用的最新nacos最好不要配置,默认就行
-
- script/config-center/config.txt配置文件
此配置信息是seata事务的相关属性
下载seata源码 选择对应版本,将script/config-center/ 下的文件 config.txt 上传服务器中 seata/下,上传script/config-center/nacos/下的nacos-config.sh文件到服务器seata/conf/下。
放哪都一样,但是config.txt文件要在nacos-config.sh文件的上一级目录。
- script/config-center/config.txt配置文件
为nacos-config.sh文件赋予执行权限
chmod +x nacos-config.sh
修改config.txt配置
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableClientBatchSendRequest=false
transport.threadFactory.bossThreadPrefix=NettyBoss
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
# 自己命名一个vgroupMapping,my_test_tx_group为自定义,怕出错可默认不修改
service.vgroupMapping.my_test_tx_group=default
service.default.grouplist=172.31.215.71:8091
service.enableDegrade=false
service.disableGlobalTransaction=false
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.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
#model改为db
store.mode=db
store.file.dir=file_store/data
store.file.maxBranchSessionSize=16384
store.file.maxGlobalSessionSize=512
store.file.fileWriteBufferCacheSize=16384
store.file.flushDiskMode=async
store.file.sessionReloadReadSize=100
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
# 改为上面创建的seata服务数据库
store.db.url=jdbc:mysql://172.31.215.70:3306/seata?useUnicode=true
# 改为自己的数据库用户名
store.db.user=root
# 改为自己的数据库密码
store.db.password=123456
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000
store.redis.host=127.0.0.1
store.redis.port=6379
store.redis.maxConn=10
store.redis.minConn=1
store.redis.database=0
store.redis.password=null
store.redis.queryLimit=100
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
client.undo.dataValidation=true
client.undo.logSerialization=jackson
client.undo.onlyCareUpdateColumns=true
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
client.undo.logTable=undo_log
client.log.exceptionRate=100
transport.serialization=seata
transport.compressor=none
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898
⚠️注意
- service.vgroupMapping.my_test_tx_group=default
中的my_test_tx_group需要与bootstrap.yml或者application.yml中配置的seata.tx-service-group的值一致。- service.vgroupMapping.my_test_tx_group=default
配置的default必须要等于registry.conf中配置的cluster="default"。- store.mode=db配置为db的方式,则需要配置db数据库方式的连接信息
store.db.url、store.db.user、store.db.password,此数据库存储下存放的表
global_table、branch_table、lock_table,用于记录全局性的事务信息- store.db.driverClassName的配置
mysql5.+使用 driverClassName = "com.mysql.jdbc.Driver"
mysql8使用 driverClassName = "com.mysql.cj.jdbc.Driver"- service.default.grouplist=ip:port为访问seata服务器的地址和端口(仅注册中心为file时使用),8091是默认端口,
也可以修改启动端口,在启动项目时加上端口:
seata-server.bat -p 8091
./seata-server.sh -p 8091- seata server需要配置集群时,只需要在启动seata server服务时指定不同的端口和节点序号即可,配置file.conf和registry.conf的内容一致。一般在生产环境中每一个seata服务放不同的服务器中,其余保持一致。
每个服务的seata启动一致
./seata-server.sh -p 8091 -n 1
-
- 执行上传命令
将config.txt配置上传至nacos,执行nacos-config.sh文件
- 执行上传命令
./nacos-config.sh -h localhost -p 8848 -t 787964a5-e21d-4eb8-9999-9bcc9244bd48 -u nacos -w nacos
-h localhost :访问nacos的ip地址
-p 8848 :nacos的端口号
-t 787964a5-e21d-4eb8-9999-9bcc9244bd48 :namespace命令空间
查看nacos配置列表是否成功。
⚠️注意
如果nacos-config.sh文件下载的是1.4.2版本的,那么执行将会报语法错误,建议使用1.3.2版本的nacos-config.sh
-
- 启动nacos
./seata-server.sh -p 8091 -n 1
- 创建需要的事务表
global_table:全局事务表
branch_table:分支信息表
lock_table:加锁的表
以上三个表需要创建在seata服务器操作的db上,即file.conf中配置的数据库。
--全局事务表--
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_gmt_modified_status` (`gmt_modified`, `status`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = INNODB
DEFAULT CHARSET = utf8;
-- 分支表
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 = utf8;
-- 锁定表
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),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`),
KEY `idx_branch_id` (`branch_id`)
) ENGINE = INNODB
DEFAULT CHARSET = utf8;
--seata新版本加的锁表
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 ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);
也可在源码 script/server/db/下找到mysql.sql直接在seata数据库执行。
undo_log:回滚日志表
在每个需要开启seata事务操作的数据库下都需要建立此表。
--日志文件表--
CREATE TABLE IF NOT EXISTS `undo_log`
(
`branch_id` BIGINT NOT NULL COMMENT 'branch transaction id',
`xid` VARCHAR(128) NOT NULL COMMENT 'global transaction id',
`context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
`rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info',
`log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status',
`log_created` DATETIME(6) NOT NULL COMMENT 'create datetime',
`log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime',
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = INNODB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';
⚠️注意
seata1.4.2之后,需要回滚的表日期类型不能使用datetime,可以使用timestamp
- 客服端配置
需要开启seata事务的客户端,需要配置seata的注册和配置中心,使用相关注解进行事务开启。
- application.yml
seata:
enabled: true
enable-auto-data-source-proxy: true #是否开启数据源自动代理,默认为true
tx-service-group: my_test_tx_group #要与配置文件中的vgroupMapping一致
service:
vgroup-mapping:
my_test_tx_group: default
registry: #registry根据seata服务端的registry配置
type: nacos #默认为file
nacos:
application: seata-server #配置自己的seata服务
cluster: default # 配置自己的seata服务cluster, 默认为 default
group: SEATA_GROUP #根据自己的seata服务配置
server-addr: 127.0.0.1:8848 #根据自己的seata服务配置
namespace: 787964a5-e21d-4eb8-9999-9bcc9244bd48 #根据自己的seata服务配置
username: nacos #根据自己的seata服务配置
password: nacos #根据自己的seata服务配置
config:
type: nacos #默认file,如果使用file不配置下面的nacos,直接配置seata.service
nacos:
group: SEATA_GROUP #配置自己的dev
server-addr: 127.0.0.1:8848 #配置自己的nacos地址
namespace: 787964a5-e21d-4eb8-9999-9bcc9244bd48 #配置自己的namespace
username: nacos #配置自己的username
password: nacos #配置自己的password
- spring boot 启动程序添加数据自动代理
使用注解:@EnableAutoDataSourceProxy
@EnableAutoDataSourceProxy
@EnableDiscoveryClient
@SpringBootApplication
public class UmappCloudServiceAppcenterApplication {
public static void main(String[] args) {
SpringApplication.run(UmappCloudServiceAppcenterApplication.class, args);
}
}
-使用注解开启事务
@GlobalLock
@GlobalTransactional
public void deleteMusicScore(String musicScoreId) {
}
⚠️⚠️⚠️注意⚠️⚠️⚠️
启动项目报错
seata :no available service ‘null‘ found, please make sure registry config correct
请检查
seata:
tx-service-group: my_test_tx_group #要与配置文件中的vgroupMapping一致
service:
vgroup-mapping:
my_test_tx_group: default
配置是否同seata服务配置一致。
seata.registry.nacos.group
seata.config.nacos.group
是否通seata服务配置一致。
can not register RM,err:can not connect to services-server.
如果在本地启动项目,seata又部署在服务器,那么请检查,在服务启动nacos的是否是否以内网启动
改成外网启动即可,但是会造成线上项目无法连接seata,所以有条件的话在测试服重新搭建seata
./seata-server.sh -p 8091 -h 127.0.0.1
NacosException: failed to req API
这个原因是Nacos重启后微服务项目启动时出现
有时候重启Nacos(大多数情况下是因为重启了机器),再启动微服务项目的服务时,后端控制台会出现NacosException: failed to req API异常。
解决办法: 现有两种解决可供参考:
一、如果未做过特殊配置,直接删除(或重命名)protocol文件夹即可
protocol文件夹在安装目录的下列位置:
...\nacos-server-1.3.0\data\
二、如果有特殊配置,修改文件raft_meta、__raft_snapshot_meta中的IP
raft_meta和__raft_snapshot_meta位置如下:
...\nacos-server-1.4.0\data\protocol\raft\naming_persistent_service\meta-data
...\nacos-server-1.4.0\data\protocol\raft\naming_persistent_service\snapshot\snapshot_7(此处可能不是_7,视具体情况而定)
注意: IP要修改为Nacos所在机器的当前IP。
项目中可能会出现的问题
⚠️⚠️⚠️
- seata事务不回滚?
- 检查依赖包是否引入正确?
- 分支事务库有没有undo_log表?
- 分支事务服务有没有引入Seata?
- 分支事务通过Feign接口调用,Feign接口处理了异常,导致主事务没有捕获到异常,导致事务无法回滚?
- 通过 RootContext.getXID() 打印每个服务的xid是否一致?
- enable-auto-data-source-proxy: true #是否开启数据源自动代理,默认为true ?
- 每个服务日志是否会显示 register RM success ?
- B服务多次执行?
feign使用get请求,请求超时会重新请求,默认五次,post只会用一次。
参考文档
seata整合nacos完成分布式的部署
分布式事务seata1.4.2使用配置
Nacos重启后微服务项目启动时后端出现NacosException: failed to req API异常解决办法
愿广大水友珍重,不掉发。