系列文章目录
JavaSE | ||
---|---|---|
基础知识、数据类型学习 | 万年历项目 | 代码逻辑训练习题 |
代码逻辑训练习题 | 方法、数组学习 | 图书管理系统项目 |
面向对象编程:封装、继承、多态学习 | 封装继承多态习题 | 常用类、包装类、异常处理机制学习 |
集合学习 | IO流、多线程学习 | 仓库管理系统JavaSE项目 |
员工管理系统、多表查询、反射实现DBHelper学习 | DML、DDL、数据库对象学习 | |
JavaWeb | ||
网络编程、各种标签、CSS学习 | ECMAScript、BOM学习 | DOM、jQuery学习 |
Servlet、JSP、Cookie、Ajax学习 | 融资管理系统JavaWeb项目 | |
框架 | ||
MyBatis框架学习 | 逆向工程、Spring框架IOC、AOP学习 | SpringMVC框架学习 |
SpringBoot框架学习 | 招聘网站框架项目 | Vue介绍、窗体内操作、窗体间操作学习 |
Vue路由配置、网络请求访问框架项目、element组件介绍学习 | 标准管理系统Vue项目 | |
微服务 | ||
Linux安装、Nginx反向代理、负载均衡学习 | Docker学习 | Jenkins学习 |
Nexus学习 | Spring Security学习 | RabbitMQ学习 |
Redis学习 | MongoDB学习 | Nacos学习 |
Spring Session学习 | Spring Gateway学习 | JSR 303学习 |
OenFeign学习 | Dubbo学习 | Hystrix学习 |
Sentinel学习 | JMeter学习 | Seata学习 |
文章目录
- 系列文章目录
- 前言
- 一、Seata介绍
- 1. Seata介绍
- 2. 三个核心角色
- 3. 四种分布式事务的解决方案
- 二、Seata安装
- 1. 拉取docker镜像
- 2. 拷贝配置文件
- 2.1 创建目录
- 2.2 保存file.conf文件
- 3. 启动nacos
- 4. 保存registry.conf文件
- 5. 创建config.txt文件
- 6. 创建nacos-config.sh文件
- 7. 导入nacos配置
- 8. 复制配置文件
- 9. 关闭并删除之前的seata容器
- 10. 开启mysql容器
- 11. 测试并创建连接
- 11. 创建seata数据库
- 12. 创建表
- 13. 启动seata
- 三、普通事务回滚
- 1. 项目基础
- 2. 更改application.yml内数据库连接属性
- 3. 创建score数据库
- 4. 运行项目
- 4.1 正常运行
- 4.2 异常运行测试回滚
- 5. 添加普通的事务回滚
- 四、Seata事务回滚
- 1. 添加依赖
- 2. 启动类添加注释
- 3. 修改application.yml配置文件
- 4. 更改事务注解
- 5. 启动项目
- 5.1 有错误时
- 5.2 无错误时
- 总结
前言
本文我们要讲述:
Seata
代码自取
通过网盘分享的文件:241005_seata.zip
链接: https://pan.baidu.com/s/1xTs4uV-3VAiRCPzBjd-Qow?pwd=k25m 提取码: k25m
一、Seata介绍
1. Seata介绍
Seata是一个用于管理分布式事务的开源框架,由阿里巴巴集团开发并维护。它提供了一套分布式事务解决方案,旨在解决分布式系统中的事务一致性问题。
2. 三个核心角色
事务协调者(Transaction Coordinator,TC):负责维护整个分布式事务的状态,包括主事务和分支事务。
事务管理器(Transaction Manager,TM):负责管理事务的生命周期,决定事务何时开始、何时结束,以及提交或回滚事务。TM负责事务的提交和回滚操作。
资源管理器(Resource Manager,RM):监控分支事务的状态并与TC进行数据交互,将分支事务的状态告知TC。
3. 四种分布式事务的解决方案
AT(Auto-Commit):自动提交模式,通过使用数据库的本地事务来实现分布式事务的一致性。
TCC(Try-Confirm-Cancel):尝试-确认-取消模式,通过定义三个阶段的业务方法来实现分布式事务的一致性。
SAGA(Saga):Saga模式是一种长事务解决方案,通过定义一系列补偿操作来实现分布式事务的一致性。
XA(eXtended Architecture):XA模式是一种经典的两阶段提交(2PC)协议,通过协调TM和RM的工作来实现分布式事务的一致性。
对于高并发项目,Seata的AT模式可能不太适用,因为在中间操作时可能会有锁的存在,从而导致效率降低。在选择Seata的解决方案时,可以根据具体的业务场景和性能需求来进行选择。
二、Seata安装
1. 拉取docker镜像
docker pull seataio/seata-server:1.3.0
2. 拷贝配置文件
docker run -d --name seata -p 8091:8091 seataio/seata-server:1.3.0
2.1 创建目录
创建/usr/local/docker/seata目录
docker cp seata:/seata-server /usr/local/docker/seata
2.2 保存file.conf文件
在/usr/local/docker/seata/seata-server/resources文件夹下找到file.conf
将file改成db
更改数据库连接属性
3. 启动nacos
docker start nacos
创建命名空间,找到id:05c721d3-1298-4204-832d-60b94a84cbbd
4. 保存registry.conf文件
group无需更改,最好不要改
namespace写刚刚拿到的命名空间ID
5. 创建config.txt文件
文件内容
#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
#Transport configuration, for client and server
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableTmClientBatchSendRequest=false
transport.enableRmClientBatchSendRequest=true
transport.enableTcServerBatchSendResponse=false
transport.rpcRmRequestTimeout=30000
transport.rpcTmRequestTimeout=30000
transport.rpcTcRequestTimeout=30000
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
transport.serialization=seata
transport.compressor=none
#Transaction routing rules configuration, only for the client
# ---------------------------------------------------
service.vgroupMapping.my_tx_group=default
# ---------------------------------------------------
#If you use a registry, you can ignore it
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false
#Transaction rule configuration, only for the client
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=true
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.rm.sagaJsonParser=fastjson
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
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
client.undo.logTable=undo_log
client.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k
#For TCC transaction mode
tcc.fence.logTableName=tcc_fence_log
tcc.fence.cleanPeriod=1h
#Log rule configuration, for client and server
log.exceptionRate=100
#Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional.
# ---------------------------------------------------
store.mode=db
store.lock.mode=db
store.session.mode=db
# ---------------------------------------------------
#Used for password encryption
store.publicKey=
#If `store.mode,store.lock.mode,store.session.mode` are not equal to `file`, you can remove the configuration block.
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
#These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
store.db.datasource=druid
store.db.dbType=mysql
# ---------------------------------------------------
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://192.168.43.8:3306/seata?useUnicode=true&rewriteBatchedStatements=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.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000
#These configurations are required if the `store mode` is `redis`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `redis`, you can remove the configuration block.
store.redis.mode=single
store.redis.single.host=127.0.0.1
store.redis.single.port=6379
store.redis.sentinel.masterName=
store.redis.sentinel.sentinelHosts=
store.redis.maxConn=10
store.redis.minConn=1
store.redis.maxTotal=100
store.redis.database=0
store.redis.password=
store.redis.queryLimit=100
#Transaction rule configuration, only for the server
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
server.distributedLockExpireTime=10000
server.xaerNotaRetryTimeout=60000
server.session.branchAsyncQueueSize=5000
server.session.enableBranchAsyncRemove=false
server.enableParallelRequestHandle=false
#Metrics configuration, only for the server
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898
需更改注释之间的数据库连接属性
6. 创建nacos-config.sh文件
#!/bin/sh
# Copyright 1999-2019 Seata.io Group.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at、
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
while getopts ":h:p:g:t:u:w:" opt
do
case $opt in
h)
host=$OPTARG
;;
p)
port=$OPTARG
;;
g)
group=$OPTARG
;;
t)
tenant=$OPTARG
;;
u)
username=$OPTARG
;;
w)
password=$OPTARG
;;
?)
echo " USAGE OPTION: $0 [-h host] [-p port] [-g group] [-t tenant] [-u username] [-w password] "
exit 1
;;
esac
done
if [ -z ${host} ]; then
host=localhost
fi
if [ -z ${port} ]; then
port=8848
fi
if [ -z ${group} ]; then
group="SEATA_GROUP"
fi
if [ -z ${tenant} ]; then
tenant=""
fi
if [ -z ${username} ]; then
username=""
fi
if [ -z ${password} ]; then
password=""
fi
nacosAddr=$host:$port
contentType="content-type:application/json;charset=UTF-8"
echo "set nacosAddr=$nacosAddr"
echo "set group=$group"
urlencode() {
length="${#1}"
i=0
while [ $length -gt $i ]; do
char="${1:$i:1}"
case $char in
[a-zA-Z0-9.~_-]) printf $char ;;
*) printf '%%%02X' "'$char" ;;
esac
i=`expr $i + 1`
done
}
failCount=0
tempLog=$(mktemp -u)
function addConfig() {
dataId=`urlencode $1`
content=`urlencode $2`
curl -X POST -H "${contentType}" "http://$nacosAddr/nacos/v1/cs/configs?dataId=$dataId&group=$group&content=$content&tenant=$tenant&username=$username&password=$password" >"${tempLog}" 2>/dev/null
if [ -z $(cat "${tempLog}") ]; then
echo " Please check the cluster status. "
exit 1
fi
if [ "$(cat "${tempLog}")" == "true" ]; then
echo "Set $1=$2 successfully "
else
echo "Set $1=$2 failure "
failCount=`expr $failCount + 1`
fi
}
count=0
COMMENT_START="#"
for line in $(cat $(dirname "$PWD")/config.txt | sed s/[[:space:]]//g); do
if [[ "$line" =~ ^"${COMMENT_START}".* ]]; then
continue
fi
count=`expr $count + 1`
key=${line%%=*}
value=${line#*=}
addConfig "${key}" "${value}"
done
echo "========================================================================="
echo " Complete initialization parameters, total-count:$count , failure-count:$failCount "
echo "========================================================================="
if [ ${failCount} -eq 0 ]; then
echo " Init nacos config finished, please start seata-server. "
else
echo " init nacos config fail. "
fi
7. 导入nacos配置
首先准备
file.conf、
registry.conf、
config.txt、
nacos-config.sh
以上四个文件备份到桌面,运行如下文件清除seata-server及其下所有文件
cd /usr/local/docker/seata
rm -rf seata-server
在seata文件夹下创建
在nacos文件夹里放入nacos-config.sh
cd /usr/local/docker/seata/nacos
chmod +x nacos-config.sh
ll
变成绿色为操作成功
sh nacos-config.sh -h 192.168.43.143 -p 8848 -g SEATA_GROUP -t 05c721d3-1298-4204-832d-60b94a84cbbd -u nacos -w nacos
会出现上图的错误,运行如下语句就能正常运行
sed -i 's/\r//' nacos-config.sh
sh nacos-config.sh -h 192.168.43.143 -p 8848 -g SEATA_GROUP -t 05c721d3-1298-4204-832d-60b94a84cbbd -u nacos -w nacos
删除seata下的所有文件(就俩文件,手动删更快)
8. 复制配置文件
创建config文件夹
将file.conf和registry.conf复制到config文件夹下
运行如下授权语句
cd /usr/local/docker/seata
chmod 777 config
9. 关闭并删除之前的seata容器
docker stop seata
docker rm seata
10. 开启mysql容器
docker start mm
11. 测试并创建连接
11. 创建seata数据库
12. 创建表
DROP TABLE
IF
EXISTS `global_table`;
CREATE TABLE `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 ( 64 ),
`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` )
);
DROP TABLE
IF
EXISTS `branch_table`;
CREATE TABLE `branch_table` (
`branch_id` BIGINT NOT NULL,
`xid` VARCHAR ( 128 ) NOT NULL,
`transaction_id` BIGINT,
`resource_group_id` VARCHAR ( 32 ),
`resource_id` VARCHAR ( 256 ),
`lock_key` VARCHAR ( 128 ),
`branch_type` VARCHAR ( 8 ),
`status` TINYINT,
`client_id` VARCHAR ( 64 ),
`application_data` VARCHAR ( 2000 ),
`gmt_create` datetime,
`gmt_modified` datetime,
PRIMARY KEY ( `branch_id` ),
KEY `idx_xid` ( `xid` )
);
DROP TABLE
IF
EXISTS `lock_table`;
CREATE TABLE `lock_table` (
`row_key` VARCHAR ( 128 ) NOT NULL,
`xid` VARCHAR ( 96 ),
`transaction_id` LONG,
`branch_id` LONG,
`resource_id` VARCHAR ( 256 ),
`table_name` VARCHAR ( 100 ),
`pk` VARCHAR ( 36 ),
`gmt_create` datetime,
`gmt_modified` datetime,
PRIMARY KEY ( `row_key` )
);
创建语句如上
13. 启动seata
docker run --name seata \
-p 8091:8091 \
-e SEATA_IP=192.168.43.143 \
-e SEATA_PORT=8091 \
-e SEATA_CONFIG_NAME=file:/root/seata-config/registry \
-v /usr/local/docker/seata/config:/root/seata-config \
-d seataio/seata-server:1.3.0
运行如下语句看到8091即为成功
docker logs -f seata
三、普通事务回滚
1. 项目基础
一些基础的项目结构无需我们编写,以提供
通过网盘分享的文件:241005_seata.zip
链接: https://pan.baidu.com/s/1xTs4uV-3VAiRCPzBjd-Qow?pwd=k25m 提取码: k25m
以下所有操作都会在两个项目同时进行,如果是单个项目进行的会额外标出
以下所有操作都会在两个项目同时进行,如果是单个项目进行的会额外标出
以下所有操作都会在两个项目同时进行,如果是单个项目进行的会额外标出
2. 更改application.yml内数据库连接属性
3. 创建score数据库
创建score数据库和user数据库
score数据库里有score表和undo_log表
user数据库里有user表和undo_log表,两者的undo_log表相同
表结构如下:
CREATE TABLE `score` (
`id` varchar(50) NOT NULL,
`name` varchar(50) NULL,
`score` double(7, 2) NULL ,
PRIMARY KEY (`id`) USING BTREE
)
CREATE TABLE `user` (
`id` varchar(50) NOT NULL,
`name` varchar(50) NULL,
`password` varchar(50) NULL,
PRIMARY KEY (`id`) USING BTREE
)
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;
4. 运行项目
4.1 正常运行
4.2 异常运行测试回滚
项目1内
添加异常语句,测试回滚
重启项目
出错了,但是发现数据库内两个都添加成功了
5. 添加普通的事务回滚
在两个项目的UserServiceImpl/ScoreServiceImpl中添加注解
@GlobalTransactional(rollbackFor = Exception.class)
再次启动项目
user的post出错添加失败
但是score的请求成功了
事务没有实现原子性
如何解决呢
四、Seata事务回滚
依旧是两个项目同时添加
1. 添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
2. 启动类添加注释
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
3. 修改application.yml配置文件
修改为如下格式
server:
port: 100
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.43.143:3306/user
username: root
password: 123456
mybatis:
mapper-locations: classpath:com/jr/mapper/*.xml
type-aliases-package: com.jr.entry
seata:
application-id: ${spring.application.name}
enabled: true
tx-service-group: my_tx_group
registry:
type: nacos
nacos:
server-addr: 192.168.43.143:8848
namespace: 05c721d3-1298-4204-832d-60b94a84cbbd
group: SEATA_GROUP
username: nacos
password: nacos
config:
type: nacos
nacos:
server-addr: 192.168.43.143:8848
namespace: 05c721d3-1298-4204-832d-60b94a84cbbd
group: SEATA_GROUP
username: nacos
password: nacos
service:
vgroup-mapping:
my_tx_group: default
feign:
httpclient:
connection-timeout: 600000
connection-timer-repeat: 30000
4. 更改事务注解
@GlobalTransactional(rollbackFor = Exception.class,timeoutMills = 300000)
5. 启动项目
5.1 有错误时
两个都不添加了
5.2 无错误时
都能请求成功
总结
本文讲述了:
Seata:项目间事务回滚
在下攸攸太上,女朋友超级可爱。