Seata1.3(AT模式) + Zookeeper +Dubbo 整合
Seata下载
注:AT模式
我下载的是源码
建立数据库 SEATA ,AT 模式需要 UNDO_LOG 表;每个和业务相关的库都要有一张 UNDO_LOG 表,后续打断点调试,能看到里面的暂存数据
SET NAMES utf8mb4
;
SET FOREIGN_KEY_CHECKS
= 0;
DROP TABLE IF EXISTS `branch_table
`;
CREATE TABLE `branch_table
` (
`branch_id
` bigint(20) NOT NULL,
`xid
` varchar(128) CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci
NOT NULL,
`transaction_id
` bigint(20) NULL DEFAULT NULL,
`resource_group_id
` varchar(32) CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci
NULL DEFAULT NULL,
`resource_id
` varchar(256) CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci
NULL DEFAULT NULL,
`lock_key
` varchar(128) CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci
NULL DEFAULT NULL,
`branch_type
` varchar(8) CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci
NULL DEFAULT NULL,
`status` tinyint(4) NULL DEFAULT NULL,
`client_id
` varchar(64) CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci
NULL DEFAULT NULL,
`application_data
` varchar(2000) CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci
NULL DEFAULT NULL,
`gmt_create
` datetime(0) NULL DEFAULT NULL,
`gmt_modified
` datetime(0) NULL DEFAULT NULL,
PRIMARY KEY (`branch_id
`) USING BTREE,
INDEX `idx_xid
`(`xid
`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci ROW_FORMAT
= Dynamic
;
DROP TABLE IF EXISTS `global_table
`;
CREATE TABLE `global_table
` (
`xid
` varchar(128) CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci
NOT NULL,
`transaction_id
` bigint(20) NULL DEFAULT NULL,
`status` tinyint(4) NOT NULL,
`application_id
` varchar(64) CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci
NULL DEFAULT NULL,
`transaction_service_group
` varchar(64) CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci
NULL DEFAULT NULL,
`transaction_name
` varchar(64) CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci
NULL DEFAULT NULL,
`timeout
` int(11) NULL DEFAULT NULL,
`begin_time
` bigint(20) NULL DEFAULT NULL,
`application_data
` varchar(2000) CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci
NULL DEFAULT NULL,
`gmt_create
` datetime(0) NULL DEFAULT NULL,
`gmt_modified
` datetime(0) NULL DEFAULT NULL,
PRIMARY KEY (`xid
`) USING BTREE,
INDEX `idx_gmt_modified_status
`(`gmt_modified
`, `status`) USING BTREE,
INDEX `idx_transaction_id
`(`transaction_id
`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci ROW_FORMAT
= Dynamic
;
DROP TABLE IF EXISTS `lock_table
`;
CREATE TABLE `lock_table
` (
`row_key
` varchar(128) CHARACTER SET utf8
COLLATE utf8_general_ci
NOT NULL,
`xid
` varchar(96) CHARACTER SET utf8
COLLATE utf8_general_ci
NULL DEFAULT NULL,
`transaction_id
` mediumtext CHARACTER SET utf8
COLLATE utf8_general_ci
NULL,
`branch_id
` mediumtext CHARACTER SET utf8
COLLATE utf8_general_ci
NULL,
`resource_id
` varchar(256) CHARACTER SET utf8
COLLATE utf8_general_ci
NULL DEFAULT NULL,
`table_name
` varchar(32) CHARACTER SET utf8
COLLATE utf8_general_ci
NULL DEFAULT NULL,
`pk
` varchar(32) CHARACTER SET utf8
COLLATE utf8_general_ci
NULL DEFAULT NULL,
`gmt_create
` datetime(0) NULL DEFAULT NULL,
`gmt_modified
` datetime(0) NULL DEFAULT NULL,
PRIMARY KEY (`row_key
`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8
COLLATE = utf8_general_ci ROW_FORMAT
= Dynamic
;
DROP TABLE IF EXISTS `undo_log
`;
CREATE TABLE `undo_log
` (
`id
` bigint(20) NOT NULL AUTO_INCREMENT,
`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(0) NOT NULL,
`log_modified
` datetime(0) NOT NULL,
`ext
` varchar(100) CHARACTER SET utf8
COLLATE utf8_general_ci
NULL DEFAULT NULL,
PRIMARY KEY (`id
`) USING BTREE,
UNIQUE INDEX `ux_undo_log
`(`xid
`, `branch_id
`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8
COLLATE = utf8_general_ci ROW_FORMAT
= Dynamic
;
SET FOREIGN_KEY_CHECKS
= 1;
源码导入idea 报错: io.seata.codec.protobuf.generated不存在 ! 解决方案:本地执行 ./mvnw clean install -DskipTests=true (Mac,Linux) 或 mvnw.cmd clean install -DskipTests=true (Win) 这个官网有讲到!!!!
修改script/config-center/下的 config.txt 文件 主要修改 store.mode=db 以及数据库的连接信息 下边这行代码是重点 service.vgroupMapping.doushanglai-service_tx_group=default 旧版本是vgroup_mapping,新版本是 vgroupMapping 如果看的帖子太多,配置文件新老掺和在一起的话要注意
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
service.vgroupMapping.doushanglai-service_tx_group=default
service.default.grouplist=127.0.0.1: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
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=hikari
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://192.168.0.162:3306/seata?useUnicode=true
store.db.user=seata
store.db.password=&Seata12
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
启动注册中心,把seata 配置写入到注册中心 如果你本地的注册中心用的nacos,在seata项目下的script/ config-center/ 下 执行脚本。
sh nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t 5a3c7d6c-f497-4d68-a71a-2e5e3340b3ca -u username - w password
这一步是把seata 的配置写进注册中心,项目此模块下的 md文档上有写。 nacos的话应该按照文档来, 一套流程走到底。
重点本人用的 Zk,同样执行上边的脚本命令
zk-config.sh -h localhost -p 2181 -z "/Users/zhangchenghui/zookeeper-3.4.14
这个脚本命令执行后,在Zk的节点上只看到了 /seata 节点,下边的子节点全是空的。 所以怀疑1.3 的zk.sh 脚本有问题,仅仅是怀疑,也可能是我自己没搞好,解决方案,代码如下:
代码写入 seata 节点(拷贝别人的)
import com
.google
.common
.base
.Charsets
;
import org
.I0Itec
.zkclient
.ZkClient
;
import org
.I0Itec
.zkclient
.exception
.ZkMarshallingError
;
import org
.I0Itec
.zkclient
.serialize
.ZkSerializer
;
import org
.apache
.zookeeper
.CreateMode
;
import java
.io
.File
;
import java
.io
.FileInputStream
;
import java
.io
.IOException
;
import java
.io
.InputStream
;
import java
.util
.Properties
;
import java
.util
.Set
;
public class ZkDataInit {
private static volatile ZkClient zkClient
;
public static void main(String
[] args
) {
if (zkClient
== null
) {
zkClient
= new ZkClient("127.0.0.1:2181", 6000, 2000);
zkClient
.setZkSerializer(new ZkSerializer() {
@Override
public byte[] serialize(Object o
) throws ZkMarshallingError
{
return String
.valueOf(o
).getBytes(Charsets
.UTF_8
);
}
@Override
public Object
deserialize(byte[] bytes
) throws ZkMarshallingError
{
return new String(bytes
, Charsets
.UTF_8
);
}
});
}
if (!zkClient
.exists("/seata")) {
zkClient
.createPersistent("/seata", true);
}
Properties properties
= new Properties();
try {
File file
=new File("C:\\Users\\zjj\\Desktop\\seata-1.3.0\\script\\config-center\\config.txt");
InputStream in
= new FileInputStream(file
);
properties
.load(in
);
Set
<Object> keys
= properties
.keySet();
for (Object key
: keys
) {
putConfig(key
.toString(), properties
.get(key
).toString());
}
} catch (IOException e
) {
e
.printStackTrace();
}
}
public static boolean putConfig(final String dataId
, final String content
) {
Boolean flag
= false;
String path
= "/seata/" + dataId
;
if (!zkClient
.exists(path
)) {
zkClient
.create(path
, content
, CreateMode
.PERSISTENT
);
flag
= true;
} else {
zkClient
.writeData(path
, content
);
flag
= true;
}
return flag
;
}
运行完之后,查看zk的 /seata 节点下是否有子节点,如图所示就对了
修改seata-server 下的 file.conf 和 registry.conf 主要修改mode以及数据库连接信息和注册方式
file.conf
## transaction log store
, only used in seata
-server
store
{
## store mode
: file、db、redis
mode
= "db"
## database store property
db
{
datasource
= "hikari"
## mysql
/oracle
/postgresql
/h2
/oceanbase etc
.
dbType
= "mysql"
driverClassName
= "com.mysql.jdbc.Driver"
url
= "jdbc:mysql://192.168.0.162:3306/seata"
user
= "seata"
password
= "&Seata12"
minConn
= 5
maxConn
= 30
globalTable
= "global_table"
branchTable
= "branch_table"
lockTable
= "lock_table"
queryLimit
= 100
maxWait
= 5000
}
}
registry.conf
registry
{
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type
= "zk"
zk
{
cluster
= "default"
serverAddr
= "127.0.0.1:2181"
sessionTimeout
= 60000
connectTimeout
= 20000
username
= ""
password
= ""
}
file
{
name
= "file.conf"
}
}
config
{
# file、nacos 、apollo、zk、consul、etcd3
type
= "zk"
zk
{
serverAddr
= "127.0.0.1:2181"
sessionTimeout
= 60000
connectTimeout
= 20000
username
= ""
password
= ""
}
file
{
name
= "file.conf"
}
}
以上确保配置没有问题,启动Server main() 直接启动 如果有一连串的getconfig 错误 检查 注册中心节点是否配置成功项目配置
springboot配置
seata
:
enabled
: true
application
-id
: $
{spring
.application
.name
}
tx
-service
-group
: doushanglai
-service_tx_group
enable
-auto
-data
-source
-proxy
: true
config
:
type
: zk
zk
:
serverAddr
: 127.0.0.1:2181
registry
:
type
: zk
zk
:
application
: $
{spring
.application
.name
}
server
-addr
: 127.0.0.1:2181
启动dubbo A服务 和 B服务
测试代码如下
@Override
@GlobalTransactional(rollbackFor
= Exception
.class)
public JsonResult
test() {
System
.out
.println("开始全部事务============================》");
goodsService
.test();
LambdaUpdateWrapper
<Task> l
= Wrappers
.lambdaUpdate();
Task t
= new Task();
t
.setGoodsId(999L
);
this.baseMapper
.update(t
, l
);
throw new RuntimeException("测试报错");
}
@Override
public JsonResult
test() {
System
.out
.println("进入商品TEST事务之前=======================================》》》");
LambdaUpdateWrapper
<Goods> u
= Wrappers
.lambdaUpdate();
Goods g
= new Goods();
g
.setStock("200");
this.baseMapper
.update(g
, u
);
System
.out
.println("进入商品TEST事务之后=======================================》》》");
return null
;
}
@PostMapping("test")
@ApiOperation(value
= "测试分布式事务【A调用B,A抛异常,AB数据都回滚】", notes
= "测试分布式事务【A调用B,A抛异常,AB数据都回滚】", produces
= "application/json")
public JsonResult
detailAuthFeeList() {
return JsonResult
.buildResult(taskService
.test());
}
结果A服务 Log
B服务 Log
数据库数据 goods表
Task表
可以在调用端打断点,观察数据库表数据的变化,还有seata 几张表的数据变化,这样更容易理解点。
初步使用已经成功,还在更深入的了解中
配置参考:官方教学
总结:
注册中心的seata配置要确定没问题,才能往下继续进行,其他注册中心没试过,seata 源码zookeeper 的写配置的脚本一直写不成功config.txt 里 service.vgroupMapping.doushanglai-service_tx_group=default 的 doushanglai-service_tx_group 配置啥样的 项目对应的服务配置就要写成啥样,修改完config.text的内容后要重新把节点写入一下注册中心(zk,其他注册中心不是很清楚)seata no available service ‘null’ found, please make sure registry config correct 这个错误检查 上边的service.vgroupMapping.doushanglai-service_tx_group=default 是否正确,是否能在注册中心的节点上找到项目结构不一样,所以仅供参考