# seata-sample
**Repository Path**: zzw6776/seata-sample
## Basic Information
- **Project Name**: seata-sample
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-11-29
- **Last Updated**: 2021-11-29
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
参考文章
项目基于dynamic-datasource示例修改而来,主要修改为增加nacos,feign
## 友情提示
1:项目的各中间件版本号都是于固定匹配的,在项目能跑起来并且没有bug的情况下千万不要私自去升级(尤其是spring-cloud-starter-alibaba-seata不要升级为最新版)
由于目前公司环境是spring-cloud-Greenwich.RELEASE的版本,所以实例以该版本为主
目前版本号对应如下
```XML
org.springframework.cloud
spring-cloud-starter-parent
Greenwich.RELEASE
com.alibaba.cloud
spring-cloud-alibaba-dependencies
2.1.4.RELEASE
pom
import
com.baomidou
dynamic-datasource-spring-boot-starter
3.4.1
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.2.0
com.alibaba
druid
1.2.6
com.alibaba
druid-spring-boot-starter
1.2.6
io.seata
seata-spring-boot-starter
1.4.2
com.alibaba.cloud
spring-cloud-starter-alibaba-seata
2.1.4.RELEASE
io.seata
seata-all
io.seata
seata-spring-boot-starter
```
# 环境搭建
友情提示:先严格按我的文档来搭建成功,部分解释我会在最后补上,网上其他的教程/官网的教程由于版本的原因有些地方是错误的
## 1.创建数据库
创建数据库名为`seata`,执行Seata的Github官方源码中提供的的MySQL数据库脚本
MySQL脚本地址:[https://github.com/seata/seata/blob/1.4.2/script/server/db/mysql.sql](https://github.com/seata/seata/blob/1.4.2/script/server/db/mysql.sql)
## 2.nacos搭建,略过
### 2.1创建nacos命名空间
### 2.2添加Server配置项:
Data Id:seataServer.properties
Group:SEATA_GROUP
内容:
> 以下参数需修改对应值
store.db.url=jdbc:mysql://xxxx:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=
store.db.password=
```YAML
ransport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableClientBatchSendRequest=true
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.my_test_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.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
store.mode=db
store.lock.mode=file
store.session.mode=file
#store.publicKey=''
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.cj.jdbc.Driver
store.db.url=jdbc:mysql://xxxx:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=
store.db.password=
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
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
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
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
log.exceptionRate=100
transport.serialization=seata
transport.compressor=none
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898
tcc.fence.logTableName=tcc_fence_log
tcc.fence.cleanPeriod=1h
```
### 2.3添加client配置项
Data Id:seata.properties
Group:SEATA_GROUP
内容:
```YAML
service.vgroupMapping.my_test_tx_group=default
```
## 3.seata搭建
#### 3.1创建registry.conf文件
其中namespace 需替换为第一步创建出来的命名空间
> 以下值需修改为nacos对应值
serverAddr = "xxxx:8848"
namespace = "b3d34adf-4018-4e31-9cf3-627d806657c5"
```YAML
registry {
type = "nacos"
nacos {
application = "seata-server"
serverAddr = "xxxx:8848"
group = "SEATA_GROUP"
namespace = "b3d34adf-4018-4e31-9cf3-627d806657c5"
cluster = "default"
username = ""
password = ""
}
}
config {
type = "nacos"
nacos {
serverAddr = "xxxx:8848"
namespace = "b3d34adf-4018-4e31-9cf3-627d806657c5"
group = "SEATA_GROUP"
username = ""
password = ""
dataId = "seataServer.properties"
}
}
```
### 3.2docker run
```YAML
docker run -d --name seata --restart=always -p 8091:8091 \
-e SEATA_IP=部署机器ip \
-e SEATA_CONFIG_NAME=file:/seata-server/resources/registry.conf \
-v 上一步创建的registry.conf位置:/seata-server/resources/registry.conf \
-v 你期望的log文件位置:/root/logs \
seataio/seata-server:1.4.2
```
启动成功后,若一切顺利可在nacos的服务列表看到seata-server
# java端接入
## 数据库准备
### 创建相关数据库
```YAML
CREATE DATABASE IF NOT EXIST seata-order;
CREATE DATABASE IF NOT EXIST seata-product;
CREATE DATABASE IF NOT EXIST seata-account;
```
> AT模式下每个数据库下脚本相关的表,seata需要undo_log来监测和回滚。
相关的脚本不用自行准备,本工程已在resources/db下面准备好,另外配合多数据源的自动执行脚本功能,应用启动后会自动执行。
### 修改yml文件
```YAML
server:
#项目端口号
port: 8080
spring:
cloud:
nacos:
config:
server-addr: xxxx:8848
namespace: b3d34adf-4018-4e31-9cf3-627d806657c5
file-extension: yaml
discovery:
server-addr: xxxx:8848
namespace: b3d34adf-4018-4e31-9cf3-627d806657c5
application:
name: tx-seata-sample-8080
main:
allow-bean-definition-overriding: true
datasource:
dynamic:
primary: order
strict: true
seata: true #开启seata代理,开启后默认每个数据源都代理,如果某个不需要代理可单独关闭
seata-mode: AT #支持XA及AT模式,默认AT
datasource:
order:
username:
password:
url: jdbc:mysql://xxxx:3306/seata_order?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
driver-class-name: com.mysql.jdbc.Driver
schema: classpath:db/schema-order.sql
account:
username:
password:
url: jdbc:mysql://xxxx:3306/seata_account?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
driver-class-name: com.mysql.jdbc.Driver
schema: classpath:db/schema-account.sql
product:
username:
password:
url: jdbc:mysql://xxxx:3306/seata_product?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
driver-class-name: com.mysql.jdbc.Driver
schema: classpath:db/schema-product.sql
test:
username: sa
password: ""
url: jdbc:h2:mem:test
driver-class-name: org.h2.Driver
seata: false #这个数据源不需要seata
seata:
enabled: true
tx-service-group: my_test_tx_group
#一定要是false
enable-auto-data-source-proxy: false
registry:
type: nacos
nacos:
server-addr: 192.168.10.48:8848
namespace: b3d34adf-4018-4e31-9cf3-627d806657c5
group: SEATA_GROUP
config:
type: nacos
nacos:
server-addr: 192.168.10.48:8848
namespace: b3d34adf-4018-4e31-9cf3-627d806657c5
group: SEATA_GROUP
#dataId: seataServer.properties
```
### 启动项目
# 部分结论
1. AT模式可以支持tidb,但是会造成脏读问题,并且脏读会导致更严重的脏写问题,如
|||
|-|-|
|线程1|线程2|
|select value where id =1
value=1
value=value+1
set value=2 where id =1||
|本地事务提交,全局事务未提交|select value where id =1
value=2
value=value+1
set value=3 where id =1|
|全局事务回滚,此时将会报错无法回滚,因为线程2已经将值改为了3,和最初版本的1无法对应,seata不知道该回滚为什么值||
具体的代码逻辑在以下位置
io.seata.rm.datasource.undo.AbstractUndoLogManager#undo
在确定AT默认会对你的业务造成什么不可挽回的损失之前不建议使用,还是建议使用XA模式,由于官方并没有给出AT模式和XA模式的性能测试差距,我也懒得测,反正满足我的线上业务场景是够了
1. seata支持高可用,只需要保证nacos以及mysql使用同一套,在多部署的情况下会同时注册到nacos上,客户端会根据映射关系去进行集群的选择,具体映射关系为:
事务分组(seata.tx-service-group的值)→nacos里的seata.properties(seata.config.nacos.dataId的值)里service.vgroupMapping.my_test_tx_group值→seata集群(registry.conf里的cluster值)
结合官方说明可能会更清楚