当前位置: 首页 > news >正文

Spring Boot 应用中的事务管理与 Feign 调用问题分析及解决

Spring Boot 应用中的事务管理与 Feign 调用问题分析及解决

  • Spring Boot 应用中的事务管理与 Feign 调用问题分析及解决
    • 问题背景
    • 问题分析
      • 可能的原因
    • 解决方案
      • 方案一:提交事务后再调用 Feign
      • 方案二:使用 `PROPAGATION_REQUIRES_NEW`
      • 方案三:使用 `@Async` 异步调用
    • 总结

Spring Boot 应用中的事务管理与 Feign 调用问题分析及解决

在微服务架构下,遇到这样的场景:一个服务需要调用另一个服务的接口来进行一系列操作,而这些操作又需要保证事务的一致性。然而,在实际开发过程中,可能会遇到一些问题,比如事务中所做的更改无法被 Feign 调用所看到。本文将以开发中遇到的一个问题当做一个例子来探讨这一问题及其解决方案。

问题背景

有一个内部商家管理模块,其主要职责是添加新的商家。在这个过程中,需要做如下几件事(已简化):

  1. 创建商家信息,并分配相应的角色。
  2. 为商家分配会员。

在这个过程中,为了保证数据的一致性和完整性,需要在方法上使用 @Transactional 注解。然而,在添加完商家之后,尝试调用 purchaseAPI.addMember 方法为商家分配会员时,发现无法获取到刚刚添加的 sys_supplier 商家信息。

问题分析

这个问题的根本原因在于事务隔离级别和 Feign 调用之间的交互。当在一个事务中执行了一系列操作后,这些操作所产生的数据更改只有在事务提交之后才会对外可见。而在同一事务中,Feign 调用实际上是在一个新的上下文中执行的,这意味着它不会看到未提交的更改。

可能的原因

  1. 事务隔离级别:默认情况下,Spring 的事务隔离级别是 ISOLATION_DEFAULT,这意味着它会使用底层数据库的默认隔离级别。如果数据库默认隔离级别是 READ_COMMITTEDREPEATABLE_READ,那么在事务中更新的数据在当前事务提交之前对其他事务不可见。

  2. Feign 调用与事务:Feign 调用实际上是在当前事务之外发生的,这意味着它不会受到当前事务的影响。因此,如果您在事务中更新了数据,Feign 调用将不会看到这些未提交的更改。

解决方案

方案一:提交事务后再调用 Feign

确保在调用 Feign 服务之前先提交事务。这可以通过将 Feign 调用放在事务范围之外来实现。例如:

@Override
public void internalSupplierAdd(InternalSupplierDTO internalSupplierDTO, LoginUser loginUser) {// ... (之前的代码)//6.添加内部供应商SysSupplier sysSupplier = new SysSupplier();BeanUtils.copyProperties(internalSupplierDTO, sysSupplier);sysSupplierMapper.insert(sysSupplier);// 提交事务PlatformTransactionManager transactionManager = TransactionAspectSupport.currentTransactionManager();TransactionDefinition def = new DefaultTransactionDefinition();TransactionStatus status = transactionManager.getTransaction(def);transactionManager.commit(status);//7.为商家分配会员Result<MemberLevle> memberLevelResult = purchaseAPI.addMemberAndLevel(tenantId);if (!memberLevelResult.isSuccess()) {//接口请求失败throw new JeecgBootException("分配会员出错!");}//...(后面的代码)}

方案二:使用 PROPAGATION_REQUIRES_NEW

如果希望在同一个方法中保持事务的原子性,但又需要确保 Feign 调用能够看到最新的数据,可以使用 PROPAGATION_REQUIRES_NEW 传播行为。这将创建一个新的事务,即使在当前事务中也是如此。

@Override
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public void internalSupplierAdd(InternalSupplierDTO internalSupplierDTO, LoginUser loginUser) {// ... (之前的代码)//6.添加商家SysSupplier sysSupplier = new SysSupplier();BeanUtils.copyProperties(internalSupplierDTO, sysSupplier);sysSupplierMapper.insert(sysSupplier);//7.为商家分配会员Result<MemberLevle> memberLevelResult = purchaseAPI.addMemberAndLevel(tenantId);if (!memberLevelResult.isSuccess()) {//接口请求失败throw new JeecgBootException("分配会员出错!");}//...(之后的代码)
}

方案三:使用 @Async 异步调用

如果分配会员的操作不是必须同步完成的,可以考虑使用异步调用来避免阻塞事务。

@Override
@Transactional(rollbackFor = Exception.class)
public void internalSupplierAdd(InternalSupplierDTO internalSupplierDTO, LoginUser loginUser) {// ... (之前的代码)//6.添加商家SysSupplier sysSupplier = new SysSupplier();BeanUtils.copyProperties(internalSupplierDTO, sysSupplier);sysSupplierMapper.insert(sysSupplier);//7.为商家分配会员asyncPurchaseService.addMemberAndLevelAsync(tenantId);//... (之后的代码)
}// 异步服务
@Service
public class AsyncPurchaseService {@Autowiredprivate PurchaseAPI purchaseAPI;@Asyncpublic void addMemberAndLevelAsync(Integer tenantId) {Result<MemberLevle> memberLevelResult = purchaseAPI.addMemberAndLevel(tenantId);if (!memberLevelResult.isSuccess()) {//接口请求失败throw new JeecgBootException("分配会员出错!");}}
}

总结

通过以上分析和解决方案,可以有效地解决事务中 Feign 调用无法看到未提交更改的问题。选择哪种解决方案取决于具体需求和场景。无论是通过手动提交事务、使用特定的事务传播行为还是使用异步调用,都可以确保数据的一致性和事务的完整性。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • C#使用NPOI进行Excel和Word文件处理(一)
  • PVE虚拟机被锁定:VM is locked解决方法
  • QtQuick Text-文本格式
  • Windows 读取wav文件字节流并播放
  • 多旋翼+四光吊舱:5Kg负载无人机技术详解
  • MySQL:行级锁
  • 车载音频开发(一):从看懂wav开始
  • DUILib 创建自定义文本编辑控件
  • 【Python】模块
  • 《Windows API每日一练》24.1 WinSock简介
  • Java中的notify()与notifyAll()区别
  • 探展2024世界人工智能大会之合合信息扫描黑科技~
  • Harmony学习(四)(应用程序框架基础)
  • 电影票房数据的获取,可以控制数量,并导出表格或csv
  • filebeat + logstash使用笔记
  • 【刷算法】从上往下打印二叉树
  • Angular4 模板式表单用法以及验证
  • Bytom交易说明(账户管理模式)
  • java B2B2C 源码多租户电子商城系统-Kafka基本使用介绍
  • Java比较器对数组,集合排序
  • Map集合、散列表、红黑树介绍
  • tab.js分享及浏览器兼容性问题汇总
  • Terraform入门 - 3. 变更基础设施
  • Vue.js源码(2):初探List Rendering
  • web标准化(下)
  • 第十八天-企业应用架构模式-基本模式
  • 后端_ThinkPHP5
  • 机器学习中为什么要做归一化normalization
  • 模仿 Go Sort 排序接口实现的自定义排序
  • 什么软件可以剪辑音乐?
  • 适配mpvue平台的的微信小程序日历组件mpvue-calendar
  • Prometheus VS InfluxDB
  • 仓管云——企业云erp功能有哪些?
  • 选择阿里云数据库HBase版十大理由
  • ​​快速排序(四)——挖坑法,前后指针法与非递归
  • ​14:00面试,14:06就出来了,问的问题有点变态。。。
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • # 详解 JS 中的事件循环、宏/微任务、Primise对象、定时器函数,以及其在工作中的应用和注意事项
  • #define,static,const,三种常量的区别
  • #define、const、typedef的差别
  • (09)Hive——CTE 公共表达式
  • (1)无线电失控保护(二)
  • (10)Linux冯诺依曼结构操作系统的再次理解
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (k8s)Kubernetes 从0到1容器编排之旅
  • (MTK)java文件添加简单接口并配置相应的SELinux avc 权限笔记2
  • (Ruby)Ubuntu12.04安装Rails环境
  • (附源码)spring boot网络空间安全实验教学示范中心网站 毕业设计 111454
  • (机器学习-深度学习快速入门)第三章机器学习-第二节:机器学习模型之线性回归
  • (九)One-Wire总线-DS18B20
  • (六)DockerCompose安装与配置
  • (学习日记)2024.01.09
  • (一) 初入MySQL 【认识和部署】