从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(五) SEATA分布式事务篇(下)应用整合shardingsphere集成seata完整代码及订单-库存完整模拟案例

简介: 从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(五) SEATA分布式事务篇(下)应用整合shardingsphere集成seata完整代码及订单-库存完整模拟案例

承接上文《从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(五) SEATA分布式事务篇(中)shardingshere 多库读写分离/分库分表下分布式事务完整代码及案例》

1.png1.png

上文中没有集成seata的情况下,跑了正常扣除库存以及生成订单的情况,下面我们来模拟上图中扣除库存成功,但是生成订单的情况,由于没有集成分布式事务,所以理论的结果肯定是库存少了,但是订单没有生成

还是使用上文中写好的业务代码,不过这次在生成订单的时候手动抛出异常,代码如下

image.png

首先清空订单数据库和还原一下库存数据库,给商品id是1的商品初始化10 个数量

1.png

然后postman 执行该接口

1.png

查看执行结果

1.png

库存服务正常

image.png

订单服务报错

image.png

库存服务库存扣除了3,订单服务没有生产订单

1.png

1.png

结果符合预期,也就是没有分布式事务情况下,数据不一致了


服务集成seata at


seata-server 配置上传到nacos


如果要让seata 识别某个或者某些服务,需要提前将一些配置上传到nacos上,上传可以使用nacos-config.sh 脚本

1.png

然后执行以下命令

sh nacos-config.sh -h 127.0.0.1

-h 是nacos 所在ip/

在nacos-condig.sh 同级目录下创建config.txt

内容如下

transport.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.mini-cloud-authentication-center_tx_group=default
service.vgroupMapping.mini-cloud-upms-center-biz_tx_group=default
service.vgroupMapping.mini-cloud-simulate-order-biz_tx_group=default
service.vgroupMapping.mini-cloud-simulate-goods-biz_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.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=db
store.session.mode=db
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.jdbc.Driver
store.db.url=jdbc:mysql://mini-cloud-mysql:3306/mini_cloud_seata?useUnicode=true&rewriteBatchedStatements=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.mode=sentinel
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=123456
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

重点两个地方 ,第一是配置服务名

1.png

一般格式是服务名+_tx_group default是默认分组


第二是修改配置模式,我这里配置的是使用db,也就是连接mysql

1.png

执行命令后会看到参数都已经传到了nacos

1.png

订单服务集成seata


由于我们集成了shardingshpere读写分离分库分表,所以不能只用传统的seata,需要使用如下maven依赖

<dependency>
  <groupId>org.apache.shardingsphere</groupId>
   <artifactId>sharding-transaction-base-seata-at</artifactId>
</dependency>
 <dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
 </dependency>

resources 目录下添加如下三个文件,库存服务也一样

1.png

file.conf

service {
  vgroupMapping.mini-cloud-simulate-order-biz_tx_group = "default" #修改事务组名称为:my_test_tx_group,和客户端自定义的名称对应
  #only support single node
  default.grouplist = "127.0.0.1:8091"
  #degrade current not support
  enableDegrade = false
  #disable
  disable = false
  disableGlobalTransaction = false
  #unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
  max.commit.retry.timeout = "-1"
  max.rollback.retry.timeout = "-1"
}

registry.conf

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"
  loadBalance = "RandomLoadBalance"
  loadBalanceVirtualNodes = 10
  nacos {
    application = "seata-server"
    serverAddr = "127.0.0.1:8848"
    group = "SEATA_GROUP"
    namespace = ""
    cluster = "default"
    username = ""
    password = ""
  }
}

seata.conf

sharding {
  transaction.seata.at.enable = true
}
client  {
    application.id =  mini-cloud-simulate-order-biz
    transaction.service.group = mini-cloud-simulate-order-biz_tx_group
}

库存服务集成seata


maven 依赖同上


 file.conf

service {
  vgroupMapping.mini-cloud-simulate-goods-biz_tx_group = "default" #修改事务组名称为:my_test_tx_group,和客户端自定义的名称对应
  #only support single node
  default.grouplist = "127.0.0.1:8091"
  #degrade current not support
  enableDegrade = false
  #disable
  disable = false
  #disable seata
  disableGlobalTransaction = false
  #unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
  max.commit.retry.timeout = "-1"
  max.rollback.retry.timeout = "-1"
}

registry.conf

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"
  loadBalance = "RandomLoadBalance"
  loadBalanceVirtualNodes = 10
  nacos {
    application = "seata-server"
    serverAddr = "127.0.0.1:8848"
    group = "SEATA_GROUP"
    namespace = ""
    cluster = "default"
    username = ""
    password = ""
  }
}

seata.conf

sharding {
  transaction.seata.at.enable = true
}
client  {
    application.id =  mini-cloud-simulate-goods-biz
    transaction.service.group = mini-cloud-simulate-goods-biz_tx_group
}

两个服务添加seataFilter,解决xid不传递问题

1.png

SeataFilter.java

@Component
public class SeataFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        String xid = req.getHeader(RootContext.KEY_XID.toLowerCase());
        boolean isBind = false;
        if (StringUtils.isNotBlank(xid)) {
            RootContext.bind(xid);
            isBind = true;
        }
        try {
            filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            if (isBind) {
                RootContext.unbind();
            }
        }
    }
    @Override
    public void destroy() {
    }
}

SeataXidRequestInterceptor.java

public class SeataXidRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        String xid = RootContext.getXID();
        if (StringUtils.isEmpty(xid)) {
            return;
        }
        List<String> fescarXid = new ArrayList<>();
        fescarXid.add(xid);
        template.header(RootContext.KEY_XID, fescarXid);
        System.err.println("添加XID:" + fescarXid);
    }
}

SeataConfiguration.java

@Configuration
public class SeataConfiguration {
    @Bean
    public RequestInterceptor requestInterceptor(){
        return new SeataXidRequestInterceptor();
    }
}

配置完毕,启动校验是否连接到seata server

1.png

信息显示注册成功,之所有有多条信息是因为我们有多个读写分离数据源,每个数据源都会注册


集成seata后再来测试一下上面的模拟订单库存失败场景


发起端订单服务接口添加全局事务注解然后重启服务

1.png

恢复商品库存为10

1.png

再测执行创建订单接口

1.png

查看结果

1.png

订单服务报错回滚


库存服务也跟着回滚

image.png

查看数据库情况,确实回滚到了10 并没有多扣除库存

1.png

以上实际案例整明seata at确实可以达到分布式事务强一直性控制

相关文章
|
8月前
|
人工智能 Java API
Java与大模型集成实战:构建智能Java应用的新范式
随着大型语言模型(LLM)的API化,将其强大的自然语言处理能力集成到现有Java应用中已成为提升应用智能水平的关键路径。本文旨在为Java开发者提供一份实用的集成指南。我们将深入探讨如何使用Spring Boot 3框架,通过HTTP客户端与OpenAI GPT(或兼容API)进行高效、安全的交互。内容涵盖项目依赖配置、异步非阻塞的API调用、请求与响应的结构化处理、异常管理以及一些面向生产环境的最佳实践,并附带完整的代码示例,助您快速将AI能力融入Java生态。
1344 12
|
前端开发 安全 开发工具
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
998 90
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
11月前
|
机器学习/深度学习 数据采集 存储
朴素贝叶斯处理混合数据类型,基于投票与堆叠集成的系统化方法理论基础与实践应用
本文探讨了朴素贝叶斯算法在处理混合数据类型中的应用,通过投票和堆叠集成方法构建分类框架。实验基于电信客户流失数据集,验证了该方法的有效性。文章详细分析了算法的数学理论基础、条件独立性假设及参数估计方法,并针对二元、类别、多项式和高斯分布特征设计专门化流水线。实验结果表明,集成学习显著提升了分类性能,但也存在特征分类自动化程度低和计算开销大的局限性。作者还探讨了特征工程、深度学习等替代方案,为未来研究提供了方向。(239字)
307 5
朴素贝叶斯处理混合数据类型,基于投票与堆叠集成的系统化方法理论基础与实践应用
|
9月前
|
人工智能 运维 负载均衡
F5发布业界首创集成式应用交付与安全平台,开启ADC 3.0新时代
F5发布业界首创集成式应用交付与安全平台,开启ADC 3.0新时代
426 0
|
9月前
|
人工智能 自然语言处理 分布式计算
AI 驱动传统 Java 应用集成的关键技术与实战应用指南
本文探讨了如何将AI技术与传统Java应用集成,助力企业实现数字化转型。内容涵盖DJL、Deeplearning4j等主流AI框架选择,技术融合方案,模型部署策略,以及智能客服、财务审核、设备诊断等实战应用案例,全面解析Java系统如何通过AI实现智能化升级与效率提升。
749 0
|
机器人 应用服务中间件 API
轻松集成私有化部署Dify文本生成型应用
Dify 是一款开源的大语言模型应用开发平台,融合了后端即服务(Backend as Service)和 LLMOps 的理念,使开发者能快速搭建生产级生成式 AI 应用。通过阿里云计算巢,用户可以一键部署 Dify 社区版,享受独享的计算和网络资源,并无代码完成钉钉、企业微信等平台的应用集成。本文将详细介绍如何部署 Dify 并将其集成到钉钉群聊机器人和企业微信中,帮助您轻松实现 AI 应用的定义与数据运营,提升工作效率。
5911 65
轻松集成私有化部署Dify文本生成型应用
|
11月前
|
缓存 前端开发 定位技术
通义灵码2.5智能体模式实战———集成高德MCP 10分钟生成周边服务地图应用
通义灵码2.5智能体模式结合高德MCP服务,实现快速构建周边服务地图应用。通过自然语言需求输入,智能体自动分解任务并生成完整代码,涵盖前端界面、API集成与数据处理,10分钟内即可完成传统开发需数小时的工作,大幅提升开发效率。
784 0
|
人工智能 数据可视化 开发者
FlowiseAI:34K Star!集成多种模型和100+组件的 LLM 应用低代码开发平台,拖拽组件轻松构建程序
FlowiseAI 是一款开源的低代码工具,通过拖拽可视化组件,用户可以快速构建自定义的 LLM 应用程序,支持多模型集成和记忆功能。
1474 14
FlowiseAI:34K Star!集成多种模型和100+组件的 LLM 应用低代码开发平台,拖拽组件轻松构建程序
|
SQL 弹性计算 DataWorks
Flink CDC 在阿里云 DataWorks 数据集成入湖场景的应用实践
Flink CDC 在阿里云 DataWorks 数据集成入湖场景的应用实践
731 6
|
存储 人工智能 NoSQL
Airweave:快速集成应用数据打造AI知识库的开源平台,支持多源整合和自动同步数据
Airweave 是一个开源工具,能够将应用程序的数据同步到图数据库和向量数据库中,实现智能代理检索。它支持无代码集成、多租户支持和自动同步等功能。
902 14