0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

保姆级教程:Spring Cloud 集成Seata分布式事务

jf_ro2CN3Fa 来源:芋道源码 2023-06-09 14:42 次阅读


环境搭建

Nacos搭建

最新版本快速搭建 使用Mysql模式

Nacos直接启动即可。控制台默认账号密码是nacos/nacos,Mysql账户密码有两个 root/rootnacos/nacos

3a2d283e-068c-11ee-962d-dac502259ad0.png

Seata搭建

Seata版本1.5.0 快速搭建

Seata1.5.0版本直接是一个SpringBoot项目,下载后修改application.yml 文件中注册中心、配置中心、存储模式配置。参考resources/application.example.yml 文件 ,修改后如下

server:
port:7091

spring:
application:
name:seata-server

logging:
config:classpath:logback-spring.xml
file:
path:${user.home}/logs/seata
extend:
logstash-appender:
destination:127.0.0.1:4560
kafka-appender:
bootstrap-servers:127.0.0.1:9092
topic:logback_to_logstash

console:
user:
username:seata
password:seata

seata:
config:
#support:nacos,consul,apollo,zk,etcd3
type:file
registry:
#support:nacos,eureka,redis,zk,consul,etcd3,sofa
type:nacos
nacos:
application:seata-server
server-addr:127.0.0.1:8848
namespace:
group:SEATA_GROUP
cluster:default
username:nacos
password:nacos
##ifuseMSENacoswithauth,mutexwithusername/passwordattribute
#access-key:""
#secret-key:""
store:
#support:file、db、redis
mode:db
db:
datasource:druid
db-type:mysql
driver-class-name:com.mysql.jdbc.Driver
url:jdbc//127.0.0.1:3306/seata?rewriteBatchedStatements=true
user:root
password:root
min-conn:5
max-conn:100
global-table:global_table
branch-table:branch_table
lock-table:lock_table
distributed-lock-table:distributed_lock
query-limit:100
max-wait:5000

>基于SpringBoot+MyBatisPlus+Vue&Element实现的后台管理系统+用户小程序,支持RBAC动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
>
>*项目地址:
>*视频教程

#server:

>基于SpringCloudAlibaba+Gateway+Nacos+RocketMQ+Vue&Element实现的后台管理系统+用户小程序,支持RBAC动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
>
>*项目地址:
>*视频教程

#service-port:8091#Ifnotconfigured,thedefaultis'${server.port}+1000'
security:
secretKey:SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
tokenValidityInMilliseconds:1800000
ignore:
urls:/,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login

创建seata数据库,执行脚本建表

----------------------------------ThescriptusedwhenstoreModeis'db'--------------------------------
--thetabletostoreGlobalSessiondata
CREATETABLEIFNOTEXISTS`global_table`
(
`xid`VARCHAR(128)NOTNULL,
`transaction_id`BIGINT,
`status`TINYINTNOTNULL,
`application_id`VARCHAR(32),
`transaction_service_group`VARCHAR(32),
`transaction_name`VARCHAR(128),
`timeout`INT,
`begin_time`BIGINT,
`application_data`VARCHAR(2000),
`gmt_create`DATETIME,
`gmt_modified`DATETIME,
PRIMARYKEY(`xid`),
KEY`idx_status_gmt_modified`(`status`,`gmt_modified`),
KEY`idx_transaction_id`(`transaction_id`)
)ENGINE=InnoDB
DEFAULTCHARSET=utf8mb4;

--thetabletostoreBranchSessiondata
CREATETABLEIFNOTEXISTS`branch_table`
(
`branch_id`BIGINTNOTNULL,
`xid`VARCHAR(128)NOTNULL,
`transaction_id`BIGINT,
`resource_group_id`VARCHAR(32),
`resource_id`VARCHAR(256),
`branch_type`VARCHAR(8),
`status`TINYINT,
`client_id`VARCHAR(64),
`application_data`VARCHAR(2000),
`gmt_create`DATETIME(6),
`gmt_modified`DATETIME(6),
PRIMARYKEY(`branch_id`),
KEY`idx_xid`(`xid`)
)ENGINE=InnoDB
DEFAULTCHARSET=utf8mb4;

--thetabletostorelockdata
CREATETABLEIFNOTEXISTS`lock_table`
(
`row_key`VARCHAR(128)NOTNULL,
`xid`VARCHAR(128),
`transaction_id`BIGINT,
`branch_id`BIGINTNOTNULL,
`resource_id`VARCHAR(256),
`table_name`VARCHAR(32),
`pk`VARCHAR(36),
`status`TINYINTNOTNULLDEFAULT'0'COMMENT'0:locked,1:rollbacking',
`gmt_create`DATETIME,
`gmt_modified`DATETIME,
PRIMARYKEY(`row_key`),
KEY`idx_status`(`status`),
KEY`idx_branch_id`(`branch_id`),
KEY`idx_xid`(`xid`)
)ENGINE=InnoDB
DEFAULTCHARSET=utf8mb4;

CREATETABLEIFNOTEXISTS`distributed_lock`
(
`lock_key`CHAR(20)NOTNULL,
`lock_value`VARCHAR(20)NOTNULL,
`expire`BIGINT,
primarykey(`lock_key`)
)ENGINE=InnoDB
DEFAULTCHARSET=utf8mb4;

INSERTINTO`distributed_lock`(lock_key,lock_value,expire)VALUES('AsyncCommitting','',0);
INSERTINTO`distributed_lock`(lock_key,lock_value,expire)VALUES('RetryCommitting','',0);
INSERTINTO`distributed_lock`(lock_key,lock_value,expire)VALUES('RetryRollbacking','',0);
INSERTINTO`distributed_lock`(lock_key,lock_value,expire)VALUES('TxTimeoutCheck','',0);

启动seata-server,控制台登录页面如下,账号密码为seata/seata

3a361552-068c-11ee-962d-dac502259ad0.png

项目搭建

业务背景

用户购买商品的业务逻辑。整个业务逻辑由3个微服务提供支持:

  • 仓储服务: 对给定的商品扣除仓储数量。
  • 订单服务: 根据采购需求创建订单。
  • 帐户服务: 从用户帐户中扣除余额。

架构

3a4771c6-068c-11ee-962d-dac502259ad0.png

业务表创建

------------------------------
--Tablestructurefort_account
------------------------------
DROPTABLEIFEXISTS`t_account`;
CREATETABLE`t_account`
(
`id`int(11)NOTNULLAUTO_INCREMENT,
`user_id`varchar(255)DEFAULTNULL,
`amount`double(14,2
)DEFAULT'0.00',
PRIMARYKEY(`id`)
)ENGINE=InnoDBAUTO_INCREMENT=2DEFAULTCHARSET=utf8;

------------------------------
--Recordsoft_account
------------------------------
INSERTINTO`t_account`
VALUES('1','1','4000.00');

------------------------------
--Tablestructurefort_order
------------------------------
DROPTABLEIFEXISTS`t_order`;
CREATETABLE`t_order`
(
`id`int(11)NOTNULLAUTO_INCREMENT,
`order_no`varchar(255)DEFAULTNULL,
`user_id`varchar(255)DEFAULTNULL,
`commodity_code`varchar(255)DEFAULTNULL,
`count`int(11)DEFAULT'0',
`amount`double(14,2
)DEFAULT'0.00',
PRIMARYKEY(`id`)
)ENGINE=InnoDBAUTO_INCREMENT=64DEFAULTCHARSET=utf8;

------------------------------
--Recordsoft_order
------------------------------

------------------------------
--Tablestructurefort_stock
------------------------------
DROPTABLEIFEXISTS`t_stock`;
CREATETABLE`t_stock`
(
`id`int(11)NOTNULLAUTO_INCREMENT,
`commodity_code`varchar(255)DEFAULTNULL,
`name`varchar(255)DEFAULTNULL,
`count`int(11)DEFAULT'0',
PRIMARYKEY(`id`),
UNIQUEKEY`commodity_code`(`commodity_code`)
)ENGINE=InnoDBAUTO_INCREMENT=2DEFAULTCHARSET=utf8;

------------------------------
--Recordsoft_stock
------------------------------
INSERTINTO`t_stock`
VALUES('1','C201901140001','水杯','1000');

------------------------------
--Tablestructureforundo_log
--注意此处0.3.0+增加唯一索引ux_undo_log
------------------------------
DROPTABLEIFEXISTS`undo_log`;
CREATETABLE`undo_log`
(
`id`bigint(20)NOTNULLAUTO_INCREMENT,
`branch_id`bigint(20)NOTNULL,
`xid`varchar(100)NOTNULL,
`context`varchar(128)NOTNULL,
`rollback_info`longblobNOTNULL,
`log_status`int(11)NOTNULL,
`log_created`datetimeNOTNULL,
`log_modified`datetimeNOTNULL,
PRIMARYKEY(`id`),
UNIQUEKEY`ux_undo_log`(`xid`,`branch_id`)
)ENGINE=InnoDBAUTO_INCREMENT=1DEFAULTCHARSET=utf8;

------------------------------
--Recordsofundo_log
------------------------------
SET
FOREIGN_KEY_CHECKS=1;

服务创建

业务服务

以order服务为例,引入依赖、配置参数、提供创建订单接口

pom.xml文件中引入依赖

<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-seataartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
dependencies>

application.properties配置参数

server.port=81
spring.application.name=order
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc//127.0.0.1:3306/seata_samples?allowPublicKeyRetrieval=true&useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=root
mybatis-plus.mapper-locations=classpath:mapper/*.xml
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

提供创建订单接口

@RequestMapping("/add")
publicvoidadd(StringuserId,StringcommodityCode,Integercount,BigDecimalamount){
Orderorder=newOrder();
order.setOrderNo(UUID.randomUUID().toString());
order.setUserId(userId);
order.setAmount(amount);
order.setCommodityCode(commodityCode);
order.setCount(count);
orderService.save(order);
}
聚合服务

business服务远程调用仓储、订单、帐户服务,完成下单流程。

1.pom.xml文件中引入依赖

<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-seataartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
dependencies>

2.application.properties配置参数

server.port=80
spring.application.name=business
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc//127.0.0.1:3306/seata_samples?allowPublicKeyRetrieval=true&useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=root
service.disableGlobalTransaction=false
# 连接超时时间
ribbon.ConnectTimeout=3000
# 响应超时时间
ribbon.ReadTimeout=5000

3.声明account、stock、order的feign接口。

@FeignClient(value="account")
publicinterfaceAccountFeign{
@RequestMapping("/account/reduce")
publicvoidreduce(@RequestParam("userId")StringuserId,@RequestParam("amount")BigDecimalamount);

}
@FeignClient(value="order")
publicinterfaceOrderFeign{
@RequestMapping("/order/add")
publicvoidadd(@RequestParam("userId")StringuserId,@RequestParam("commodityCode")StringcommodityCode,@RequestParam("count")Integercount,@RequestParam("amount")BigDecimalamount);

}
@FeignClient(value="stock")
publicinterfaceStockFeign{
@RequestMapping("/stock/deduct")
publicvoiddeduct(@RequestParam("commodityCode")StringcommodityCode,@RequestParam("count")Integercount);

}

4.全局事务开启,调用feign接口

@Autowired
privateOrderFeignorderFeign;

@Autowired
privateStockFeignstockFeign;

@Autowired
privateAccountFeignaccountFeign;

@GlobalTransactional
@RequestMapping("/toOrder")
publicvoidtoOrder(StringuserId,StringcommodityCode,Integercount,BigDecimalamount){
accountFeign.reduce(userId,amount);
stockFeign.deduct(commodityCode,count);
orderFeign.add(userId,commodityCode,count,amount);
}

测试验证

当前资金账户4000,库存1000,模拟用户购买商品2000个,消费4000,业务调用后,数据库数据状态应该如下:

  • 用户资金满足4000,数据库更新用户资金为0。
  • 商品库存不满足2000个,异常。
  • business服务提交全局回滚。
  • 资金服务回滚操作,更新资金为4000。

验证:

1.浏览器输入地址请求访问

  • http://127.0.0.1/business/toOrder?userId=1&commodityCode=C201901140001&count=2000&amount=4000

2.account、stock服务日志观察。

3a5f22e4-068c-11ee-962d-dac502259ad0.png3a88011e-068c-11ee-962d-dac502259ad0.png

3.数据库数据依然为原始状态。

3aacbdec-068c-11ee-962d-dac502259ad0.png

注意事项

1.Seata1.5版本的mysql驱动是5.7,需要为8,在libs文件夹删除mysql-connector-java-5.xx.jar,替换mysql-connector-java-8.xx.jar即可

2.Spring Boot &Spring Cloud&Spring Cloud Alibaba版本兼容问题

Spring Cloud Alibaba版本说明

3ab9d7fc-068c-11ee-962d-dac502259ad0.png

3.druid和数据驱动版本兼容

通过druid仓库版本查看各依赖版本说明

3acad4da-068c-11ee-962d-dac502259ad0.png

代码仓库

  • https://gitee.com/codeWBG/springcloud_alibaba


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 代码
    +关注

    关注

    30

    文章

    4556

    浏览量

    66814
  • 管理系统
    +关注

    关注

    1

    文章

    1936

    浏览量

    34425
  • spring
    +关注

    关注

    0

    文章

    333

    浏览量

    14161

原文标题:保姆级教程:Spring Cloud 集成 Seata 分布式事务

文章出处:【微信号:芋道源码,微信公众号:芋道源码】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    EDAS再升级!全面支持Spring Cloud应用

    摘要: 近日,阿里中间件(Aliware)的企业分布式应用服务EDAS宣布再次升级,全面支持Spring Cloud应用。点此查看原文:[url=]http://click.aliy
    发表于 02-02 15:20

    微服务架构下分布式事务解决方案 —— 阿里GTS

    ,完成事务的发起与结束。GTS RM完成事务分支的创建、提交、回滚等操作。GTS Server主要负责分布式事务的整体推进,事务生命周期的管
    发表于 03-16 11:14

    一行代码,保障分布式事务一致性—GTS:微服务架构下分布式事务解决方案

    主要完成事务的发起与结束。GTS RM完成分支事务的开启、提交、回滚等操作。GTS Server主要负责分布式事务的整体推进,事务生命周期的
    发表于 06-05 19:14

    Dubbo Cloud Native 之路的实践与思考

    发现的能力,就功能性而言,Zuul 和 Gateway 自身并不具备这样的特性,需要搭配 Eureka 这样组件,它们更像服务路由器的角色。分布式配置左边和中间的四种技术均为 Spring Cloud
    发表于 07-05 16:05

    浅谈分布式缓存技术

    存储成本分布式缓存应用场景1,用于缓存网页的内容片段,包括HTML,CSS和图像等,主要用于社交网站;2,缓存系统作为ORM框架的二缓存提供外部服务,减轻了数据库的负载压力,加快了应用访问;3.缓存
    发表于 11-16 15:45

    详解Spring事务管理

    在学习spring事务管理时,我忍不住要问,spring为什么进行事务管理,spring怎么进行的事务
    发表于 07-12 06:54

    如何高效完成HarmonyOS分布式应用测试?

    Testing从测试标准、测试服务及云测服务三个方面提供分布式应用测试的解决方案。下面,我们将逐一介绍。1. 测试标准测试标准定义APP的入门测试要求,重点覆盖消费者用户最关心的HarmonyOS特征
    发表于 12-13 18:07

    分布式事务控制的原理实例分析

    对于分布式数据库而言,分布式事务控制是重点和难点,一直以来没有成熟的方案可以突破CAP理论,几乎每个分布式数据库研发团队都在分布式
    发表于 09-28 19:04 0次下载
    <b class='flag-5'>分布式</b><b class='flag-5'>事务</b>控制的原理实例分析

    从代码角度详解Seata AT事务模式的流程

    Seata 四种事务模式中,AT 事务模式是阿里体系独创的事务模式,对业务无侵入,也是 Seata 用户最多的一种
    的头像 发表于 09-29 10:08 921次阅读

    分布式链路跟踪Sleuth与Zipkin

    Spring Cloud Sleuth 也为我们提供了一套完整的解决方案。在本章中,我们将详细介绍如何使用 Spring Cloud Sleuth + Zipkin 来为我们的微服务架
    的头像 发表于 01-13 10:11 466次阅读

    spring分布式框架有哪些

    Spring分布式框架。 Spring Cloud Spring Cloud是基于
    的头像 发表于 11-16 10:58 365次阅读

    springclould分布式教程

    Spring Cloud是一个基于Spring Boot的分布式系统开发工具,它提供了一系列的分布式系统解决方案,可以帮助开发者快速构建和部
    的头像 发表于 11-16 10:59 226次阅读

    springcloud如何实现分布式

    Spring Cloud是基于Spring Boot开发的一套分布式系统解决方案,它主要包括了多个子项目,如服务注册与发现、配置中心、负载均衡、断路器、路由等等。通过使用
    的头像 发表于 11-16 11:01 370次阅读

    springcloud分布式事务解决方案

    Spring Cloud是一套用于构建分布式系统的开源框架,它提供了一系列组件和工具,可以帮助开发人员快速构建和管理基于微服务架构的应用程序。在分布式系统中,
    的头像 发表于 11-16 11:03 1114次阅读

    springcloud 分布式事务解决方案实例

    么都执行成功,要么都执行失败。本文将介绍如何使用Spring Cloud来实现分布式事务。 在分布式系统中,使用数据库
    的头像 发表于 12-03 16:32 566次阅读