版本说明

本例于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相关推荐

  1. SpringCloud整合TX-LCN5.0.2使用LCN模式实现分布式事务

    一.TM配置 pom.xml文件中添加依赖: <dependency><groupId>com.codingapi.txlcn</groupId><artif ...

  2. seata1.3.0版本整合nacos踩过的深坑—not support register type: null (SpringBoot、Cloud、CloudAlibaba版本兼容使用)?

    问题:在搭建分布式事务seata版本时报错,提示 NotSupportYetException: not support register type: null:从异常提示可以看出应该是版本兼容问题 ...

  3. 最详细SpringCloud+nacos整合Seata1.4.2 实现分布式事务

    SpringCloud整合Seata 实现分布式事务 Seata 简介和工作原理 看seata官网吧 安装Seata 使用浏览器访问"https://github.com/seata/sea ...

  4. 分布式事务解决方案之 Alibaba Seata1.3.0 seata-server 1.3.0

    分布式事务解决方案之 Alibaba Seata1.3.0 一 Seata 是什么? Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata 将为用户提供了 ...

  5. SpringCloud 整合 Dubbo

    目录 1.介绍 2.代码实现 2.1 抽取公共模块 2.2 改造服务提供者 2.3 改造服务消费者 3.启动测试 1.介绍 Dubbo有两种使用方式: 1.基于SOA的思想,将一个单体架构拆分为web ...

  6. SpringCloud 整合 Seata

    <分布式事务>https://blog.csdn.net/u011060911/article/details/122210788上面的文章系统介绍了分布式事务相关的理论知识,本文则通过代 ...

  7. SpringCloud - 整合Nacos启动报错Consider defining a bean of type IClientConfig

    SpringCloud - 整合Nacos启动报错Consider defining a bean of type IClientConfig 前言 一. 尝试解决Bug的几种不合适方案 1.1 添加 ...

  8. SpringCloud 整合 TX-LCN分布式事务框架

    微服务兴起,分布式事务也成为亟需解决的难题,业界解决方案很多,今天介绍一个我目前觉得最好用的TX-LCN. 官网地址:http://www.txlcn.org/zh-cn/ 一.TX-LCN介绍 TX ...

  9. springcloud整合seata

    springcloud整合seata 一.背景 二.项目结构 三.实现功能: 四.项目使用到的技术 五.整合步骤 1.引入spring-cloud-starter-alibaba-seata jar包 ...

最新文章

  1. 实验研究信标无线电能输出功率的因素
  2. (chap1 网络基础知识)网络的构成要素:(4-6)集线器和3层交换机
  3. 【CV】计算机视觉领域有哪些不错的博客?
  4. mysql的错误号大全
  5. java 监听写文件的进度_java读取文件显示进度条的实现方法
  6. 炸金花比牌规则java_陈陈来给你们炸金花的简易纸牌规则教学与心态指导
  7. winform响应时间最长是多少分钟_当詹姆斯退役时,他的总出场时间会达到多少分钟?...
  8. 2018-07-06笔记(LNMP配置)
  9. rockemq 发送延迟消息_58分布式消息队列WMB设计与实践
  10. Spring之注入集合值
  11. text-align 属性,输入框数字向右靠
  12. win10装sql2000卡在选择配置_小编为你作答win10系统安装SQL2000卡在MADC不动
  13. 理解JavaScript内联命名函数---var fun = function f() {}
  14. EDI 公开课:EDI 系统集成之数据库方案
  15. SSM框架Web程序的流程(Spring SpringMVC Mybatis)
  16. wifi信号增强android,WiFi信号增强大师
  17. 3.0_Linux如何连接网络
  18. 昊鼎王五:高级运维工程师的成长之路,总有一款适合你^_^
  19. Maven入门教程(十七)-Maven多Moudle项目创建
  20. Android接收短信和发送短信

热门文章

  1. 5 种值得收藏的图像压缩器工具,可不降低质量压缩图像
  2. 内存泄漏是个什么狗东西
  3. Presentation 技巧总结
  4. 基于大学生内卷行为的调查研究
  5. 基于微信小程序的拍卖系统源码
  6. 前端开发面试题整理(摘抄)
  7. 海康监控系统行为识别服务器,基于海康视频监控系统的目标检测和跟踪
  8. php邮箱类,php邮件类(PHPMailer)使用心得
  9. ext4magic恢复工具ext4
  10. 【定量分析、量化金融与统计学】统计推断基础(2)---样本均值分布、中心极限定理、正态分布