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

解决Spring事务中RPC调用无法回滚的问题

文章目录

    • 问题分析
    • 解决方案
    • 实现原理解析
    • 执行流程说明
    • 运行实例
      • 正常流程执行
      • 执行异常流程
    • 关键优势

在分布式系统开发中,我们经常会遇到本地事务与远程服务调用结合的场景。当本地事务包含RPC调用时,如果事务回滚,RPC调用已经执行就会导致数据不一致。本文将介绍如何优雅地解决这个问题。

问题分析

考虑以下场景:有方法A、B、C组成一个大事务,其中B方法需要调用RPC服务。如果C方法执行失败导致整个事务回滚,但RPC已经调用并提交,就会造成数据不一致。

核心问题是:RPC调用默认会在本地事务提交前执行,无法参与事务回滚

解决方案

Spring提供了事务同步机制(TransactionSynchronization),允许我们注册回调函数,在事务完成后执行特定操作。利用这个机制,我们可以确保:

只有当本地事务成功提交后,才会执行RPC调用;如果事务回滚,则不执行RPC

以下是实现代码:

package cn.bb.mydemo.service;import cn.bb.mydemo.entity.Student;
import cn.bb.mydemo.mapper.StudentMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;import java.time.LocalTime;
import java.util.concurrent.CompletableFuture;@Service
public class StudentService {@Autowiredprivate StudentMapper studentMapper;@Transactional(rollbackFor = Exception.class)public void saveWithRpcAfterTx(String name) {// 1. 执行本地数据库操作Student student = new Student();student.setName(name);studentMapper.insert(student);// 2. 注册事务同步回调:在事务提交后异步执行RPCTransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {@Overridepublic void afterCommit() {// 使用CompletableFuture异步执行RPC,避免阻塞事务提交CompletableFuture.runAsync(() -> doRpc(name));}});}@Transactional(rollbackFor = Exception.class)public void run(String name) {Student student = new Student();student.setName(name);studentMapper.insert(student);}@Transactional(rollbackFor = Exception.class)public void allRun() {// 调用不同方法组成一个大事务this.saveWithRpcAfterTx("Alice");this.run("a");this.run("b");System.out.println("本地事务已提交");// int i = 1 / 0; // 取消注释此行会触发异常,导致事务回滚}// 模拟RPC调用private void doRpc(String name) {System.out.println(LocalTime.now() + " RPC调用收到:" + name);}
}

测试代码验证实现效果:

@SpringBootTest
class TxAsyncTest {@Autowiredprivate StudentService studentService;@Testvoid shouldRpcAfterTxCommit2() throws InterruptedException {// 调用组合事务方法studentService.allRun();// 等待异步RPC执行完成Thread.sleep(20000);}
}

实现原理解析

这个解决方案的核心在于TransactionSynchronizationManagerTransactionSynchronizationAdapter的使用:

  1. TransactionSynchronizationManager:Spring提供的事务同步管理器,允许注册回调函数监听事务生命周期事件

  2. TransactionSynchronizationAdapter:事务同步适配器,我们可以重写其中的关键方法:

    • afterCommit():事务成功提交后执行
    • afterCompletion():事务完成后执行(无论成功或失败)
    • beforeCommit():事务提交前执行
  3. 异步执行:使用CompletableFuture.runAsync()确保RPC调用不会阻塞事务提交过程

执行流程说明

当调用allRun()方法时,执行流程如下:

  1. 开启数据库事务
  2. 执行saveWithRpcAfterTx():插入数据库记录并注册事务同步回调
  3. 执行run()两次:插入两条额外记录
  4. 如果没有异常,事务提交
  5. 事务提交后,触发注册的afterCommit()回调
  6. 异步执行RPC调用
  7. 如果任何步骤发生异常,事务回滚,不会触发RPC调用

运行实例

正常流程执行

在这里插入图片描述

在这里插入图片描述
新增了ab 并且 rpc是最后被调用的 虽然这个方法被放在了中间

执行异常流程

在这里插入图片描述
在这里插入图片描述
数据也没有添加什么 事务被回滚了 这就保证了我们的需求【当事务被提交 rpc才被调用 否则错误就不执行rpc 防止重复数据的生成】

关键优势

  1. 数据一致性:确保本地事务与RPC调用的最终一致性
  2. 非侵入性:不需要修改现有事务管理代码
  3. 异步执行:不影响事务性能
  4. 简单可靠:基于Spring内置机制,无需额外框架

这种方法特别适合那些需要保证本地数据与远程服务数据一致性的场景,是解决大事务中RPC无法回滚问题的优雅方案。

http://www.lryc.cn/news/596883.html

相关文章:

  • 解构未来金融:深入剖析DeFi与去中心化交易所(DEX)的技术架构
  • 【音视频学习】五、深入解析视频技术中的像素格式:颜色空间、位深度、存储布局
  • LoRA 低秩矩阵实现参数高效的权重更新
  • 新手向:Pycharm的使用技巧
  • python3写一个异步http接口服务调用大模型(async, sanic)---6.1
  • Hexo - 免费搭建个人博客04 - 创建另一个私人仓库,对Hexo项目进行版本管理
  • Log4j CVE-2021-44228 漏洞复现详细教程
  • Sklearn 机器学习 线性回归
  • 20250704-基于强化学习在云计算环境中的虚拟机资源调度研究
  • OpenCV 零基础到项目实战 | DAY 2:图像预处理全解析
  • 基于Seata的微服务分布式事务实战经验分享
  • 7月23号打卡
  • 四、cv::Mat的介绍和使用
  • 【趣味解读】淘宝登录的前后端交互机制:Cookie-Session 如何保障你的账户安全?
  • 密码学中的概率论与统计学:从频率分析到现代密码攻击
  • 从8h到40min的极致并行优化:Spark小数据集UDTF处理的深度实践与原理剖析
  • 通用图片 OCR 到 Word API 数据接口
  • AI黑科技:GAN如何生成逼真人脸
  • Jquery、Vue 、Ajax、axios、Fetch区别
  • 微算法科技(NASDAQ: MLGO)研究量子机器学习算法 (Quantum Machine Learning Algorithms),加速机器学习任务
  • 【OpenCV篇】OpenCV——02day.图像预处理(1)
  • 基于Trae IDE与MCP实现网页自动化测试的最佳实践
  • 神经网络和机器学习的一些基本概念
  • CLI 与 IDE 编码代理比较:提升开发效率的两种路径
  • PDF转Word的简单方法
  • Fluent许可与硬件绑定的解决方法
  • 2027.7.23深搜算法复习总结
  • Semantic Kernel实现调用Kernel Memory
  • 多模态Embedding技术
  • 视觉BPE统一多模态理解-北大