高度细化的SAGA模式实现:基于Spring Boot与RabbitMQ的跨服务事务

场景与技术栈

场景:电商系统中的订单创建流程,涉及订单服务(Order Service)、库存服务(Inventory Service)、支付服务(Payment Service)。

技术栈:

  • Java 11

  • Spring Boot 2.7.0

  • MySQL 8.0

  • RabbitMQ

项目结构与组件
  • order-service

  • inventory-service

  • payment-service

  • saga-coordinator

代码实现

1. Saga Coordinator

@SpringBootApplicationpublic class SagaCoordinatorApplication {    public static void main(String[] args) {        SpringApplication.run(SagaCoordinatorApplication.class, args);    }}@Service@RequiredArgsConstructorpublic class SagaService {    private final SagaOrderService sagaOrderService;    private final SagaInventoryService sagaInventoryService;    private final SagaPaymentService sagaPaymentService;    private final SagaTransactionRepository sagaTransactionRepository;    public void placeOrder(Long orderId, Long productId, int quantity, double amount) throws ExecutionException, InterruptedException {        SagaTransaction transaction = new SagaTransaction();        transaction.setOrderId(orderId);        transaction.setProductId(productId);        transaction.setQuantity(quantity);        transaction.setAmount(amount);        transaction.setStatus(SagaTransaction.Status.INITIATED);        sagaTransactionRepository.save(transaction);        CompletableFuture.runAsync(() -> sagaOrderService.createOrder(transaction))            .thenRunAsync(() -> sagaInventoryService.decreaseInventory(transaction))            .thenRunAsync(() -> sagaPaymentService.charge(transaction))            .exceptionally(ex -> {                rollback(transaction);                throw new RuntimeException("Saga failed", ex);            });    }    private void rollback(SagaTransaction transaction) {        CompletableFuture.runAsync(() -> sagaPaymentService.refund(transaction))            .thenRunAsync(() -> sagaInventoryService.increaseInventory(transaction))            .thenRunAsync(() -> sagaOrderService.cancelOrder(transaction))            .exceptionally(ex -> {                transaction.setStatus(SagaTransaction.Status.FAILED);                sagaTransactionRepository.save(transaction);                throw new RuntimeException("Rollback failed", ex);            });    }}

2. SagaOrderService

@Servicepublic class SagaOrderService {    private final OrderService orderService;    private final RabbitTemplate rabbitTemplate;    @Autowired    public SagaOrderService(OrderService orderService, RabbitTemplate rabbitTemplate) {        this.orderService = orderService;        this.rabbitTemplate = rabbitTemplate;    }    public void createOrder(SagaTransaction transaction) {        // 创建订单逻辑        // ...        // 发送创建订单完成的消息        rabbitTemplate.convertAndSend("order.create", transaction);    }    public void cancelOrder(SagaTransaction transaction) {        // 取消订单逻辑        // ...        // 发送取消订单完成的消息        rabbitTemplate.convertAndSend("order.cancel", transaction);    }}

3. SagaInventoryService

@Servicepublic class SagaInventoryService {    private final InventoryService inventoryService;    private final RabbitTemplate rabbitTemplate;    @Autowired    public SagaInventoryService(InventoryService inventoryService, RabbitTemplate rabbitTemplate) {        this.inventoryService = inventoryService;        this.rabbitTemplate = rabbitTemplate;    }    public void decreaseInventory(SagaTransaction transaction) {        // 扣减库存逻辑        // ...        // 发送扣减库存完成的消息        rabbitTemplate.convertAndSend("inventory.decrease", transaction);    }    public void increaseInventory(SagaTransaction transaction) {        // 增加库存逻辑        // ...        // 发送增加库存完成的消息        rabbitTemplate.convertAndSend("inventory.increase", transaction);    }}

4. SagaPaymentService

@Servicepublic class SagaPaymentService {    private final PaymentService paymentService;    private final RabbitTemplate rabbitTemplate;    @Autowired    public SagaPaymentService(PaymentService paymentService, RabbitTemplate rabbitTemplate) {        this.paymentService = paymentService;        this.rabbitTemplate = rabbitTemplate;    }    public void charge(SagaTransaction transaction) {        // 收款逻辑        // ...        // 发送收款完成的消息        rabbitTemplate.convertAndSend("payment.charge", transaction);    }    public void refund(SagaTransaction transaction) {        // 退款逻辑        // ...        // 发送退款完成的消息        rabbitTemplate.convertAndSend("payment.refund", transaction);    }}
SagaTransaction Entity
@Entitypublic class SagaTransaction {    @Id    @GeneratedValue(strategy = GenerationType.IDENTITY)    private Long id;    private Long orderId;    private Long productId;    private int quantity;    private double amount;    private Status status; // INITIATED, COMPLETED, ROLLING_BACK, ROLLED_BACK, FAILED    // Getters & Setters}
消息队列监听

在每个微服务中,需要添加消息队列的监听器,以便在接收到消息时执行相应的操作。例如,在order-service中:

@Componentpublic class OrderSagaListener {    private final SagaOrderService sagaOrderService;    @Autowired    public OrderSagaListener(SagaOrderService sagaOrderService) {        this.sagaOrderService = sagaOrderService;    }    @RabbitListener(queues = "order.create")    public void handleOrderCreate(SagaTransaction transaction) {        sagaOrderService.createOrder(transaction);    }    @RabbitListener(queues = "order.cancel")    public void handleOrderCancel(SagaTransaction transaction) {        sagaOrderService.cancelOrder(transaction);    }}
额外细节
  • 为确保事务的一致性,可以使用RabbitMQ的发布确认(Publisher Confirms)机制。

  • 每个微服务的数据库事务应该使用@Transactional注解来保证ACID属性。

  • 需要设计失败重试和事务状态检查机制,确保在故障恢复时能够正确地执行补偿操作。

通过上述设计,SAGA模式与RabbitMQ的结合,不仅能够处理跨服务的事务,还能够通过消息队列实现服务解耦和消息的异步处理,提高系统的稳定性和可扩展性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/55413.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Thinkphp/Laravel旅游景区预约系统的设计与实现

目录 技术栈和环境说明具体实现截图设计思路关键技术课题的重点和难点:框架介绍数据访问方式PHP核心代码部分展示代码目录结构解析系统测试详细视频演示源码获取 技术栈和环境说明 采用PHP语言开发,开发环境为phpstudy 开发工具notepad并使用MYSQL数据库…

Qt的互斥量用法

目的 互斥量的概念 互斥量是一个可以处于两态之一的变量:解锁和加锁。这样,只需要一个二进制位表示它,不过实际上,常常使用一个整型量,0表示解锁,而其他所有的值则表示加锁。互斥量使用两个过程。当一个线程(或进程)…

国际 Android WPS Office v18.13 解锁版

WPS Office 移动版,设计不断优化,性能再次提升!融入Google Android最新设计标准,Material Design设计风格,完美支持沉浸式!简化文档操作,全新移动办公力作。全新界面更清晰舒适,功能…

MySQL 库的操作

温馨提示:非特殊情况不要删除和随意修改数据库 清除MySQL历史命令:system clear 增删数据库 增删数据库 登录MySQL:mysql -u root -pMySQL数据目录:/var/lib/mysql查看当前数据库列表:show databases;创建数据库&#…

代码随想录 | Day26 | 二叉树:二叉搜索树中的插入操作删除二叉搜索树中的节点修剪二叉搜索树

代码随想录 | Day26 | 二叉树:二叉搜索树中的插入操作&&删除二叉搜索树中的节点&&修剪二叉搜索树 主要学习内容: 二叉搜索树的插入删除操作 701.二叉搜索树中的插入操作 701. 二叉搜索树中的插入操作 - 力扣(LeetCode&…

CSS3练习--电商web

免责声明:本文仅做分享! 目录 小练--小兔鲜儿 目录构建 SEO 三大标签 Favicon 图标 布局网页 版心 快捷导航(shortcut) 头部(header) logo 导航 搜索 购物车 底部(footer&#xff0…

C(九)while循环 --- 军训匕首操情景

匕首操,oi~oi~oi~~~~~ 接下来的几篇推文,杰哥记录的是三大循环结构的运行流程及其变式。 本篇的主角是while循环。👉 目录: while循环 的组成、运行流程及其变式关键字break 和 continue 在while 循环中的作用while 循环的嵌套题目…

微信小程序 图片的上传

错误示范 /*从相册中选择文件 微信小程序*/chooseImage(){wx.chooseMedia({count: 9,mediaType: [image],sourceType: [album],success(res) {wx.request({url:"发送的端口占位符",data:res.tempFiles[0].tempFilePath,method:POST,success(res){//请求成功后应该返…

搜索引擎相关的一段实习经历

0 前言 就是跟搜索相关的一段经历。主要工作就是建立倒排索引库相关的一些简单内容。 又翻到了以前的工作,权作纪念。 就是简单的封装cpp的库供python语言调用。 反正就是很多版本问题等等吧各种鬼问题。 我感觉这个思路可能还是待考证。 跨语言的调用我感觉还是不…

STM32 Hal库SDIO在FATFS使用下的函数调用关系

STM32 Hal库SDIO在FATFS使用下的函数调用关系 本文并不将FATFS的相关接口操作,而是将HAL在使用FATFS通过SDIO外设管理SD卡时,内部函数的调用逻辑,有助于当我们使用CUBEMX生成FATFS读取SD卡的代码时无法运行时Debug。本文也会说明一些可能出现…

Study--Oracle-09--部署Openfiler存储服务器

一路走来,所有遇到的人,帮助过我的、伤害过我的都是朋友,没有一个是敌人。 免费的存储服务器软件有FreeNAS 和 Openfiler。 其中Freenas的网站上只有i386及amd64的版本,也就是说Freenas不能支持64位版本的Intel CPU,而Openfiler则提供更全面的版本支持,在其网站上…

一个真实可用的登录界面!

需要工具: MySQL数据库、vscode上的php插件PHP Server等 项目结构: login | --backend | --database.sql |--login.php |--welcome.php |--index.html |--script.js |--style.css 项目开展 index.html: 首先需要一个静态网页&#x…

Linux线程(七)线程安全详解

当我们编写的程序是一个多线程应用程序时,就不得不考虑到线程安全的问题,确保我们编写的程序是一个线程安全(thread-safe)的多线程应用程序,什么是线程安全以及如何保证线程安全?带着这些问题,本…

zookeeper选举kafka集群的controller

zookeeper选举kafka集群的controller目录 文章目录 zookeeper选举kafka集群的controller目录前言一、实操体验controller的选举二、模拟controller选举四、删除controller节点 前言 kafka集群的controller是kafka集群中一个有特殊作用的broker,负责整个kafka集群的…

树结构的应用

在数据结构中,树是一种抽象数据类型,它是由节点组成的,每个节点包含一个值和指向其子节点的引用。 树结构在计算机科学和现实世界中无处不在,它帮助我们以一种直观和逻辑的方式组织信息。无论是在软件开发、数据库管理还是日常生…

数据结构--线性表(顺序结构)

1.线性表的定义和基本操作 1.1线性表以及基本逻辑 1.1.1线性表 (1)n(>0)个数据元素的有限序列,记作(a1,a2,...an),其中ai是线性表中的数据元素,n是表的长度。 (2)…

Redis数据库与GO(二):list,set

一、list(列表) list(列表)是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。List本质是个链表, list是一个双向链表,其元素是有序的,元…

51单片机系列-串口(UART)通信技术

🌈个人主页: 羽晨同学 💫个人格言:“成为自己未来的主人~” 并行通信和串行通信 并行方式 并行方式:数据的各位用多条数据线同时发送或者同时接收 并行通信特点:传送速度快,但因需要多根传输线&#xf…

计算机视觉学习路线:从基础到进阶

计算机视觉学习路线:从基础到进阶 计算机视觉(Computer Vision)是人工智能和机器学习领域中重要的分支,致力于让计算机能够理解和分析图像、视频等视觉信息。随着深度学习的发展,计算机视觉的应用变得越来越广泛&…

速盾:游戏被攻击怎么办?

随着游戏行业的发展,游戏被攻击的情况也越来越多见。游戏被攻击可能导致游戏服务器崩溃、用户数据泄露、游戏体验受影响等问题。作为游戏开发者或运营商,面对游戏被攻击的情况,应该采取一系列的措施来应对。 首先,要及时发现游戏…