# springcloud_seata_demo
**Repository Path**: hwm0717/springcloud_seata_demo
## Basic Information
- **Project Name**: springcloud_seata_demo
- **Description**: seata 分布式事物框架demo
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-11-23
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
`seata`如果不是很了解的话可以直接到官网查看官方文档说明:[http://seata.io/zh-cn/docs/overview/what-is-seata.html](http://seata.io/zh-cn/docs/overview/what-is-seata.html)
如果你还对`SpringBoot`、`Dubbo`、`Nacos`、`Seata`、` Mybatis` 不是很了解的话,这里我为大家整理个它们的官网网站,如下
- SpringBoot:[https://spring.io/projects/spring-boot](https://spring.io/projects/spring-boot)
- Nacos:[https://nacos.io/zh-cn/docs/quick-start.html](https://nacos.io/zh-cn/docs/quick-start.html)
- Seata:[https://seata.io/zh-cn/](https://seata.io/zh-cn/)
- MyBatis:[http://www.mybatis.org/mybatis-3/zh/index.html](http://www.mybatis.org/mybatis-3/zh/index.html)
**本例子主要模块为以下版本:**
springboot版本:2.2.5.RELEASE
spring-cloud版本:Hoxton.SR3
spring-cloud-alibaba版本:2.2.1.RELEASE
seata版本:1.4.0
nacos版本:1.4.0
如果还没安装好nacos环境的可以参考文档:[nacos下载与安装](https://blog.csdn.net/u012946310/article/details/110043529)
**整个业务逻辑由4个微服务提供支持:**
- 库存服务(storage):扣除给定商品的存储数量。
- 订单服务(order):根据购买请求创建订单。
- 帐户服务(account):借记用户帐户的余额。
- 业务服务(business):处理业务逻辑。
- 公共模块(common):公共模块。
## 一、下载并安装seata-server
**1,下载seata**
[https://github.com/seata/seata/releases](https://github.com/seata/seata/releases)

**2,解压并移动到 /usr/local/ 目录下**
```bash
tar -zxvf seata-server-1.4.0.tar.gz
mv seata seata-1.4.0
mv seata-1.4.0/ /usr/local/
cd /usr/local/seata-1.4.0/
```
**3,修改 conf/registry.conf 配置**
目前seata支持如下的file、nacos 、apollo、zk、consul的注册中心和配置中心。这里我们以`nacos` 为例。
将 type 改为 nacos
```bash
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
loadBalance = "RandomLoadBalance"
loadBalanceVirtualNodes = 10
nacos {
application = "seata-server"
serverAddr = "192.168.2.112:8848"
group = "SEATA_GROUP"
namespace = ""
cluster = "default"
username = ""
password = ""
}
}
config {
# file、nacos 、apollo、zk、consul、etcd3
type = "nacos"
nacos {
serverAddr = "192.168.2.112:8848"
namespace = ""
group = "SEATA_GROUP"
username = ""
password = ""
}
}
```
- serverAddr = "192.168.2.112:8848" :nacos 的地址
- namespace = "" :nacos的命名空间默认为``
- cluster = "default" :集群设置未默认 `default`
**4,修改 config.txt 文件**
config.txt 配置文件需要自行下载,下载后放到seata根目录下面,下载地址:[https://github.com/seata/seata/blob/develop/script/config-center/config.txt](https://github.com/seata/seata/blob/develop/script/config-center/config.txt)
```bash
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.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.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
store.mode=file
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
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true
store.db.user=username
store.db.password=password
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
log.exceptionRate=100
transport.serialization=seata
transport.compressor=none
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898
```
配置的详细说明参考官网:[http://seata.io/zh-cn/docs/user/configurations.html](http://seata.io/zh-cn/docs/user/configurations.html)
这里主要修改了如下几项:
- store.mode :存储模式 默认file 这里我修改为db 模式 ,并且需要三个表`global_table`、`branch_table`和`lock_table`
- store.db.driverClassName=com.mysql.jdbc.Driver
- store.db.db-type=mysql : 存储数据库的类型为`mysql`
- store.db.url=jdbc:mysql://192.168.2.112:3306/seata_config?useUnicode=true : 修改为自己的数据库`url`、`port`、`数据库名称`
- store.db.user=root :数据库的账号
- store.db.password=123456 :数据库的密码
- service.vgroupMapping.order-seata-tx-group=default
- service.vgroupMapping.account-seata-tx-group=default
- service.vgroupMapping.storage-seata-tx-group=default
- service.vgroupMapping.business-seata-tx-group=default
`注意:如果mysql版本为8.0以上的版本,需要使用8.x以上的驱动包,并且将 store.db.driverClassName=com.mysql.jdbc.Driver 配置改为 store.db.driverClassName=com.mysql.cj.jdbc.Driver`
`然后直接到seata/lib目录下,将8版本的jar包粘贴到目录下`
**db模式下的所需的三个表的数据库脚本下载地址:[https://github.com/seata/seata/blob/develop/script/server/db/mysql.sql](https://github.com/seata/seata/blob/develop/script/server/db/mysql.sql)**
**5、将 Seata 配置添加到 Nacos 中**
脚本下载地址:[https://github.com/seata/seata/blob/develop/script/config-center/nacos/nacos-config.sh](https://github.com/seata/seata/blob/develop/script/config-center/nacos/nacos-config.sh)
下载后将脚本放到 seata bin/ 目录下,并将脚本权限改成具有可执行权限
```bash
cd bin
chmod 755 nacos-config.sh
```
执行 nacos-config.sh 脚本,将配置上传到nacos
```bash
sh ./nacos-config.sh
```
看到输出如下内容,说明脚本已经执行成功

登陆到nacos控制台也能够看到上传的配置内容

**6、使用db模式启动 seata**
```bash
sh seata-server.sh -h 192.168.2.112 -p 8091 -m db
```
```bash
Options:
--host, -h
The host to bind,主机绑定ip,nacos的注册地址
Default: 0.0.0.0
--port, -p
The port to listen.
Default: 8091
--storeMode, -m
log store mode : file、db
Default: file
--help
```
Server端存储模式(store.mode)现有file、db、redis三种,file模式无需改动,直接启动即可,下面专门讲下db和redis启动步骤。
注: file模式为单机模式,全局事务会话信息内存中读写并持久化本地文件root.data,性能较高;
db模式为高可用模式,全局事务会话信息通过db共享,相应性能差些;
redis模式Seata-Server 1.3及以上版本支持,性能较高,存在事务信息丢失风险,请提前配置合适当前场景的redis持久化配置.
## 二、代码构建
`项目地址:`[https://gitee.com/hwm0717/springcloud_seata_demo](https://gitee.com/hwm0717/springcloud_seata_demo)
**4个微服务提供支持:**
- 库存服务(storage):扣除给定商品的存储数量。
- 订单服务(order):根据购买请求创建订单。
- 帐户服务(account):借记用户帐户的余额。
- 业务服务(business):处理业务逻辑。
- 公共模块(common):公共模块。
`我们只需要在业务处理的方法handleBusiness添加一个注解 @GlobalTransactional 即可实现分布式事物的处理`
请求逻辑架构:

`pom.xml文件`
```bash
4.0.0
pom
org.springframework.boot
spring-boot-starter-parent
2.2.5.RELEASE
seata.demo
springcloud_seata_demo
1.0-SNAPSHOT
1.8
2.2.5.RELEASE
8.0.21
1.1.22
1.4.0
Hoxton.SR3
2.2.1.RELEASE
business
account
order
storage
common
org.projectlombok
lombok
provided
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-openfeign
com.baomidou
mybatis-plus-boot-starter
3.3.0
com.github.pagehelper
pagehelper-spring-boot-starter
1.2.12
mysql
mysql-connector-java
${mysql.connector.java.version}
com.alibaba
druid-spring-boot-starter
${druid-spring-boot-starter.version}
log4j
log4j
1.2.17
com.spring4all
swagger-spring-boot-starter
1.7.0.RELEASE
com.alibaba.cloud
spring-cloud-alibaba-seata
2.2.0.RELEASE
io.seata
seata-spring-boot-starter
io.seata
seata-spring-boot-starter
${seata.version}
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-dependencies
${springboot.version}
pom
import
com.alibaba.cloud
spring-cloud-alibaba-dependencies
${spring-cloud-alibaba.version}
pom
import
```
**1,库存服务:**
```bash
@Data
public class TStorage {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String commodityCode;
private String name;
private Integer count;
}
```
```bash
public interface TStorageMapper extends BaseMapper {
/**
* 扣减商品库存
* @Param: commodityCode 商品code count扣减数量
* @Return:
*/
int decreaseStorage(@Param("commodityCode") String commodityCode, @Param("count") Integer count);
}
```
```bash
@RestController
@RequestMapping("/storage")
@Slf4j
public class StorageServiceImpl extends ServiceImpl {
@PostMapping("/decreaseStorage")
@GlobalTransactional
@Transactional
public ObjectResponse decreaseStorage(@RequestBody CommodityDTO commodityDTO) {
log.info("seata全局xid={}", RootContext.getXID());
int storage = baseMapper.decreaseStorage(commodityDTO.getCommodityCode(), commodityDTO.getCount());
ObjectResponse