SpringCloud整合Seata1.4.0
版本说明
本例于windows基于Nacos配置注册、MybatisPlus、Hikari数据源,数据库为Mysql,示例代码为Seata的AT模式。案例代码GitHub地址spring-cloud-alibaba
具体版本:
seata 1.4.0
SpringBoot 2.3.6.RELEASE
SpringCloud Hoxton.SR9
SpringCloudAlibaba 2.2.3.RELEASE
MybatisPlus 3.3.2
下载资源
从Seata Release下载目前最新版的1.4.0发行包和源码
Seata配置
Server
1、解压seata-server-1.4.0文件,进入/seata/conf,将register.conf内容修改为
registry {# file 、nacos 、eureka、redis、zk、consul、etcd3、sofatype = "nacos"nacos {application = "seata-server"serverAddr = "127.0.0.1:8848"group = "SEATA_GROUP"namespace = "56c94dbe-7fbe-49c2-b456-170001455569"cluster = "default"username = "nacos"password = "nacos"}}config {# file、nacos 、apollo、zk、consul、etcd3type = "nacos"nacos {serverAddr = "127.0.0.1:8848"namespace = "56c94dbe-7fbe-49c2-b456-170001455569"group = "SEATA_GROUP"username = "nacos"password = "nacos"}
}
此处为设置seata使用nacos进行注册与配置
registry.nacos.namespace
为nacos中的命名空间,可以自行创建命名空间后,替换此处的namespace
进入/bin,打开cmd,运行
seata-server.bat -p 9000 -m file
运行成功后,将会在nacos服务列表中显示
2、数据库建seata库即表
数据库新建yuli-seata
数据库,用来存放seata全局数据
进入script/server/db,在yuli-seata
库中运行mysql.sql
文件,最终得到三张表
3、初始化配置文件同步到nacos中,请先启动nacos,再执行此操作
解压seata的source code,进入script/config-center,修改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.spring-cloud-demo=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=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
store.db.url=jdbc:mysql://127.0.0.1:3306/yuli-seata?useUnicode=true
store.db.user=root
store.db.password=root
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.spring-cloud-demo=default
spring-cloud-demo为自定义的事务组
store.mode=db
状态由数据库管理
store.db.url=jdbc:mysql://127.0.0.1:3306/yuli-seata?useUnicode=true
数据库连接地址
store.db.user=root
数据库用户名
store.db.password=root
数据库密码
windows环境下可以通过python环境执行py脚本,也可通过git环境执行sh脚本,本文使用git bash
进入解压后的源码包中/script/config-center/nacos
打开git bash窗口,执行
sh nacos-config.sh -h localhost -p 8848 -t 56c94dbe-7fbe-49c2-b456-170001455569 -u nacos -w nacos
-h
nacos’s host
p
nacos’s 端口
-t
nacos namespace命名空间id
-u
nacos用户名
-w
nacos密码
执行成功:
在nacos中查看配置
可以发现配置散落一地,别诧异,这是正常的。但是希望后期会有所优化吧,毕竟太散乱
Client
引入依赖,注意本例父pom中引入了spring-cloud-alibaba-dependencies,且定义了版本号,所以此处未手动定义版本号。需要查看完整代码的请移步文章头部提到的代码地址。
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
在项目的bootstrap.yml文件中增加如下配置
seata:enabled: trueapplication-id: ${spring.application.name}tx-service-group: spring-cloud-demo #此处配置自定义的seata事务分组名称enable-auto-data-source-proxy: true #开启数据库代理config:type: nacosnacos:server-addr: ${spring.cloud.nacos.discovery.server-addr}namespace: ${spring.cloud.nacos.discovery.namespace}group: SEATA_GROUPregistry:type: nacosnacos:application: seata-serverserver-addr: ${spring.cloud.nacos.discovery.server-addr}namespace: ${spring.cloud.nacos.discovery.namespace}
${}
为获取本文件中定义变量
如${spring.cloud.nacos.discovery.server-addr}
,在本例中已经有设置为localhost:8848
注意seata.tx-service-group
和上文config.txt
文件中service.vgroupMapping.spring-cloud-demo=default
有对应关系,
关系为spring-cloud-demo
配置代理数据源
package cn.javayuli.mybatis.config;import com.zaxxer.hikari.HikariDataSource;
import io.seata.rm.datasource.DataSourceProxy;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;import javax.sql.DataSource;/*** 对分布式事务seata配置的数据源代理** @author hanguilin*/
@Configuration
@ConditionalOnClass(HikariDataSource.class)
public class DataSourceProxyConfig {/*** 原生datasource前缀取"spring.datasource"** @return*/@Bean@ConfigurationProperties(prefix = "spring.datasource")public DataSource hikariDataSource() {HikariDataSource hikariDataSource = new HikariDataSource();return hikariDataSource;}/*** 构造datasource代理对象,替换原来的datasource** @param hikariDataSource* @return*/@Primary@Bean("dataSource")public DataSourceProxy dataSourceProxy(DataSource hikariDataSource) {return new DataSourceProxy(hikariDataSource);}
}
启动类排除DataSourceAutoConfiguration
类
package cn.javayuli;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.SpringCloudApplication;/*** 订单服务* * @author hanguilin*/
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
@SpringCloudApplication
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}
}
DEMO
本例举很经典的例子:下订单时需要生成订单信息和扣减商品库存。
结构图
调用关系图:
项目结构图:
api-common
公共调用,其中api-common-mybatis包含mybatis、seata、mysql-connect-java依赖,以及seata代理数据源配置,需要连接数据库的服务直接在pom中引入其项目即可
api-gateway
基于springcloud gateway的网关服务
api-provider
业务服务,由其发起远程调用,调用订单、库存服务
api-provider-order
订单服务,可以创建订单信息
api-provider-stock
库存服务,可以扣减商品数量
库表
项目库表
yuli-order
库中tb_order
表为订单信息表
yuli-stock
库中tb_stock
表为库存信息表
undo_log
为seata事务中重要的表,在每个应用中都需要创建一张
,如果是单库,就用一张undo_log
表即可
undo_log
表建表语句
CREATE TABLE `undo_log` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT,`branch_id` BIGINT(20) NOT NULL,`xid` VARCHAR(100) NOT NULL COLLATE 'utf8_general_ci',`context` VARCHAR(128) NOT NULL COLLATE 'utf8_general_ci',`rollback_info` LONGBLOB NOT NULL,`log_status` INT(11) NOT NULL,`log_created` DATETIME NOT NULL,`log_modified` DATETIME NOT NULL,`ext` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8_general_ci',PRIMARY KEY (`id`) USING BTREE,UNIQUE INDEX `ux_undo_log` (`xid`, `branch_id`) USING BTREE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=56;
tb_order
CREATE TABLE `tb_order` (`id` INT(11) NOT NULL AUTO_INCREMENT,`no` VARCHAR(64) NULL DEFAULT NULL COMMENT '订单编号' COLLATE 'utf8_general_ci',`remark` VARCHAR(255) NULL DEFAULT NULL COMMENT '备注' COLLATE 'utf8_general_ci',`create_time` DATETIME NULL DEFAULT NULL COMMENT '创建时间',`update_time` DATETIME NULL DEFAULT NULL COMMENT '修改时间',`del_flag` CHAR(1) NULL DEFAULT NULL COLLATE 'utf8_general_ci',PRIMARY KEY (`id`) USING BTREE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=39;
tb_stock
CREATE TABLE `tb_stock` (`id` INT(11) NOT NULL AUTO_INCREMENT,`goods` VARCHAR(255) NULL DEFAULT NULL COMMENT '物资名称' COLLATE 'utf8_general_ci',`number` INT(10) NULL DEFAULT NULL COMMENT '库存数量',`remark` VARCHAR(255) NULL DEFAULT NULL COMMENT '备注' COLLATE 'utf8_general_ci',`create_time` DATETIME NULL DEFAULT NULL COMMENT '创建时间',`update_time` DATETIME NULL DEFAULT NULL COMMENT '更新时间',`del_flag` CHAR(1) NULL DEFAULT NULL COLLATE 'utf8_general_ci',PRIMARY KEY (`id`) USING BTREE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=2;
接口
订单服务暴露接口
/*** 创建订单** @param no 订单编号* @return*/
@PostMapping("/order/save")
public String doSaveOrder (@RequestParam("no") String no) {Order order = new Order();order.setNo(no);// 保存订单orderService.save(order);return "success";
}
库存服务暴露接口
根据物资现有数量减去出售数量,如果库存不够就会抛出异常
/*** 扣减库存** @param goods 物资* @param number 扣除量* @return*/
@GetMapping("/deduct")
public String doDeductionStock(@RequestParam("goods") String goods, @RequestParam("number") int number) {Stock stock = orderService.getOne(Wrappers.lambdaQuery(Stock.class).eq(Stock::getGoods, goods));Integer stockNumber = stock.getNumber();Integer left = stockNumber - number;if (stockNumber == 0 || left < 0) {throw new RuntimeException("商品数量不足");}stock.setNumber(left);orderService.updateById(stock);return "success";
}
业务服务feign接口
/*** 远程调用库存服务** @author hanguilin*/
@FeignClient(contextId = "remoteOrderService", value = "api-provider-order",fallbackFactory = RemoteOrderServiceFallbackFactory.class)
public interface RemoteOrderService {/*** 创建订单** @param no 订单编号* @return*/@PostMapping("/order/save")String doSaveOrder (@RequestParam("no") String no);
}
/*** 远程调用库存服务** @author hanguilin*/
@FeignClient(contextId = "remoteStockService", value = "api-provider-stock",fallbackFactory = RemoteStockServiceFallbackFactory.class)
public interface RemoteStockService {/*** 扣减库存** @param goods 物资* @param number 扣除量* @return*/@GetMapping("/stock/deduct")String doDeductionStock(@RequestParam("goods") String goods, @RequestParam("number") int number);
}
业务服务暴露接口
/*** 下订单** @param no 订单编号* @param goods 物资* @return*/
@GlobalTransactional
@PostMapping("/business/create/order")
public String doCreateOrder (@RequestParam("no") String no, @RequestParam("goods") String goods) {return businessService.createOrder(no, goods);
}
/*** 下订单** @param no 订单编号* @param goods 物资* @return*/
@Override
public String createOrder(String no, String goods) {remoteOrderService.doSaveOrder(no);remoteStockService.doDeductionStock(goods, 1);return "success";
}
@GlobalTransactional
为seata的注解,表示开启全局事务
网关配置
nacos中api-gateway-dev.yml
server:port: 8001
spring:cloud:gateway:routes:- id: api-provideruri: lb://api-providerpredicates:- Path=/provider/**filters:- RewritePath=/provider/(?<segment>.*), /$\{segment}- id: api-provider-orderuri: lb://api-provider-orderpredicates:- Path=/provider-order/**filters:- RewritePath=/provider-order/(?<segment>.*), /$\{segment}- id: api-provider-stockuri: lb://api-provider-stockpredicates:- Path=/provider-stock/**filters:- RewritePath=/provider-stock/(?<segment>.*), /$\{segment}
场景测试
库存充足情况下会正常插入一条订单信息和将商品库存数减1
启动nacos->seata->(api-gateway、api-provider、api-provider-order、api-provider-stock)
端口说明
api-gateway:8001
api-provider:8000
api-provider-order:8002
api-provider-stock:8003
发送请求,路径http://localhost:8001/provider/business/create/order,走网关请求
订单成功插入一条数据
库存成功扣减(1->0)
此时将订单号修该一下,再请求,此时库存服务就会抛出异常
订单信息未插入
可看到订单服务控制台显示分支事务回滚,二阶段回滚,说明全局事务在其中起到了相应作用
SpringCloud整合Seata1.4.0相关推荐
- SpringCloud整合TX-LCN5.0.2使用LCN模式实现分布式事务
一.TM配置 pom.xml文件中添加依赖: <dependency><groupId>com.codingapi.txlcn</groupId><artif ...
- seata1.3.0版本整合nacos踩过的深坑—not support register type: null (SpringBoot、Cloud、CloudAlibaba版本兼容使用)?
问题:在搭建分布式事务seata版本时报错,提示 NotSupportYetException: not support register type: null:从异常提示可以看出应该是版本兼容问题 ...
- 最详细SpringCloud+nacos整合Seata1.4.2 实现分布式事务
SpringCloud整合Seata 实现分布式事务 Seata 简介和工作原理 看seata官网吧 安装Seata 使用浏览器访问"https://github.com/seata/sea ...
- 分布式事务解决方案之 Alibaba Seata1.3.0 seata-server 1.3.0
分布式事务解决方案之 Alibaba Seata1.3.0 一 Seata 是什么? Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata 将为用户提供了 ...
- SpringCloud 整合 Dubbo
目录 1.介绍 2.代码实现 2.1 抽取公共模块 2.2 改造服务提供者 2.3 改造服务消费者 3.启动测试 1.介绍 Dubbo有两种使用方式: 1.基于SOA的思想,将一个单体架构拆分为web ...
- SpringCloud 整合 Seata
<分布式事务>https://blog.csdn.net/u011060911/article/details/122210788上面的文章系统介绍了分布式事务相关的理论知识,本文则通过代 ...
- SpringCloud - 整合Nacos启动报错Consider defining a bean of type IClientConfig
SpringCloud - 整合Nacos启动报错Consider defining a bean of type IClientConfig 前言 一. 尝试解决Bug的几种不合适方案 1.1 添加 ...
- SpringCloud 整合 TX-LCN分布式事务框架
微服务兴起,分布式事务也成为亟需解决的难题,业界解决方案很多,今天介绍一个我目前觉得最好用的TX-LCN. 官网地址:http://www.txlcn.org/zh-cn/ 一.TX-LCN介绍 TX ...
- springcloud整合seata
springcloud整合seata 一.背景 二.项目结构 三.实现功能: 四.项目使用到的技术 五.整合步骤 1.引入spring-cloud-starter-alibaba-seata jar包 ...
最新文章
- 实验研究信标无线电能输出功率的因素
- (chap1 网络基础知识)网络的构成要素:(4-6)集线器和3层交换机
- 【CV】计算机视觉领域有哪些不错的博客?
- mysql的错误号大全
- java 监听写文件的进度_java读取文件显示进度条的实现方法
- 炸金花比牌规则java_陈陈来给你们炸金花的简易纸牌规则教学与心态指导
- winform响应时间最长是多少分钟_当詹姆斯退役时,他的总出场时间会达到多少分钟?...
- 2018-07-06笔记(LNMP配置)
- rockemq 发送延迟消息_58分布式消息队列WMB设计与实践
- Spring之注入集合值
- text-align 属性,输入框数字向右靠
- win10装sql2000卡在选择配置_小编为你作答win10系统安装SQL2000卡在MADC不动
- 理解JavaScript内联命名函数---var fun = function f() {}
- EDI 公开课:EDI 系统集成之数据库方案
- SSM框架Web程序的流程(Spring SpringMVC Mybatis)
- wifi信号增强android,WiFi信号增强大师
- 3.0_Linux如何连接网络
- 昊鼎王五:高级运维工程师的成长之路,总有一款适合你^_^
- Maven入门教程(十七)-Maven多Moudle项目创建
- Android接收短信和发送短信