分布式事务之远程调用服务异常后的事务回滚

前言


在这里插入图片描述

 同一个商品在很多仓库都有库存 库存-锁定是剩余的商品数量

下了一个订单 里面有多件商品 要分别找每个商品是否还有库存
在一个订单下的多个商品只要有一个是没有库存的 整个订单就要回滚

在这里插入图片描述

在这里插入图片描述

 写Sql语句的时候 先不用找到具体的字段关系 可以先用数字来代替 然后在数据库哪里好使了就焕

 在这里插入图片描述

 抛异常来判断返回的值是什么 而不是用 if else来判断

在这里插入图片描述

在这里插入图片描述

1. 分布式事务

异常回滚在同一个服务器中很简单
如果在一个逻辑下包含本服务自身事务异常回滚+远程服务器里的事务异常回滚
就涉及到分布式异常
在分布式事务中
A1
B
A2

上面的逻辑就涉及远程调用B服务器的事务异常逻辑
两个情况:
情况一:A无异常 数据库正常操作 B因为远程调用返回给A的是操作失败
A以为B事务异常 所以A操作数据库逻辑回滚 数据库无变动
但其实B只是 因为远程操作时长过长导致失败 网络抖动等都是原因 B已经在数据库里做了操作 数据库记录已经变化

情况二:
A2出现异常 抛出异常 希望 A1和 B都事务回滚 数据库操作
A1还好说因为都在同一段代码里 可以直接回滚 但是B无法直接回滚 因为B在另一个服务器里 除非我们调用B 否则无法回滚 因为事务是一个链接

在这里插入图片描述

在这里插入图片描述

 不要求强一致 远程的库存扣了就扣了 无法立即在同一时间回滚 但是可以等一会慢慢的 最终一致 远程库存回滚把减了的库存再加回来就行 不用此时事务同时回滚

 一两个系统不可用 为了保证稳定性 我们会将部分客户转到降级页面 (当前页面不可用)

2. 分布式事务的解决方案

1)刚性事务 ACID 强一致 的2PC

有一个中间管理资源 问每一微服务的本地事务 是否准备好了
当每一个微服务的本地事务都回复准备好了 才开始提交事务

一旦中间管理资源 发现有那个本地食物没提交成功 就全部回滚
这就是强一致性 详细管理所有 并且锁定所有

2)柔性事务 BASE 最终一致性

本地服务保存订单 远程锁库存 本地服务扣积分
最终一致性就保证远程的服务 本来加了200 为了模拟事务回滚 就在代码里检测到异常后-200 达成回滚的效果

try{
    调用远程服务操作接口获得准备数据
}confirm{
   确认提交 真的操作数据
}
catch{
  发现整个流程其他阶段报异常,模拟事务回滚  
  调用远程服务操作接口 【把刚才的操作如果是+ 现在就-  恢复原样】
}

2.1 springcloud alibaba seata 解决分布式事务

既然事务是一个与数据库的链接
如果想要用seta 去控制分布式事务问题
seta势必要管理好 各服务与数据库的链接 核心 管理好数据源 datasource

seta 的管理就是包装 数据源 将数据源包装过后再使用
下面不适用SpringBoot 2.0 因为已经循环依赖bean

在这里插入图片描述

 但意思就是 上面与配置文件关联的这个duriddatasource 以参数的形式传进 下面的@PRIMARY 以该bean为主的 方法里 通过代理包装原本的数据源 是seta代理过后的数据源成为主数据源

在这里插入图片描述

 datasourceAutoConfiguration 是 spring 里的 数据源配置类
里面还维护了其他配置类
配置类中注入了很多数据源 hrika就是spring默认的数据源
上面的注解的意思是 如果我们自己没有配数据源 就会默认走这个数据源

我们可以模仿上面的createDataSource也写一个配置类 注入到容器里 我们自己配数据源 就不会走到上面那个默认的数据源了
这样就能全面的防御和使用 达到分布式事务的目的

但是seta 的 核心 是获得全局锁 就是对所有的事务【即与数据库的链接】串行化操作 此时此刻要把这个请求所到的微服务与数据库的链接锁住 等到整个大业务没问题释放锁
但是全局的锁住事务 就无法达到并发 此时若再有其他请求过来也需要这个数据库的链接 就要等待
所以这个分布式事务的内核是一个串行化 请求需要等待上一个请求的事务释放链接

2. 柔性事务-最大努力通知型-支持大并发

上面的代码也还是在用try去感知 在本地去通知 和 回滚
有没有什么工具可以借助 让这个工具去分发 通知 并且不用写同步代码 现在要感知异常后等待所有事务回滚才结束
MQ 在这个大流程里 如果三个业务有一个失败了 可以发送到MQ里 其他两个业务监听TOPIC发现这个业务失败了 要回滚 就消费消息 执行回滚catch代码 支持并发 有一个失败了 其他两个回滚是异步的 不像上面的手写代码 要等待同步

3. 存在的问题

如果在本地事务中调用远程服务,那样本地该事务的操作就与提供远程服务的接口强依赖了,如果远程服务出现了问题,那么就会拖长事务,事务长时间没有提交,数据库连接就不会被释放,随着太多的数据库连接被占用,可能会导致数据库崩溃。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在Feign远程调用中,事务控制是一个比较复杂的问题。Feign本身并不直接支持事务控制,因为它是一个用于远程服务调用的工具,而事务控制通常是在应用程序的业务逻辑层面进行处理的。 如果你需要在Feign远程调用中实现事务控制,你可以考虑以下几种方式: 1. 分布式事务管理器:使用分布式事务管理器,如Spring Cloud的分布式事务管理器或者Seata等,来管理Feign远程调用中的事务。这样可以确保在跨服务调用时,事务的一致性和隔离性得到保证。 2. 本地事务补偿:在Feign远程调用中,可以通过本地事务补偿的方式来实现事务控制。即在调用方的本地事务中,记录下需要调用的远程服务的操作,如果本地事务成功提交,则再调用远程服务进行相应的操作。如果本地事务失败,则进行相应的事务回滚。 3. 异步消息:使用异步消息的方式来实现事务控制。即在调用方的本地事务中,将需要调用的远程服务的操作发送到消息队列中,然后由消息队列来保证事务的一致性和隔离性。 需要注意的是,以上方法都需要在应用程序的业务逻辑层面进行相应的处理和配置,具体的实现方式会根据你的业务需求和技术栈而有所不同。同时,对于分布式事务的处理,还需要考虑到分布式事务的一致性和性能等方面的问题。 综上所述,Feign本身并不直接支持事务控制,但可以通过使用分布式事务管理器、本地事务补偿或异步消息等方式来实现Feign远程调用的事务控制。具体的实现方式需要根据你的业务需求和技术栈来确定。 #### 引用[.reference_title] - *1* *2* *3* [微服务组件之Feign远程服务调用](https://blog.csdn.net/Wang_Dong_Liang/article/details/127633506)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

慕城南风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值