分布式事务在电商项目中的应用

一、分布式事务基础概念

1. 定义

在微服务架构中,一个业务功能跨多个服务 / 数据库时,需保证对多个资源服务器的操作要么全部成功,要么全部失败 ,本质是保证跨节点的数据一致性

2. 电商核心应用场景

  1. 下单链路 :用户下单时冻结库存(订单服务 + 库存服务,跨服务事务)
  2. 支付链路 :支付成功后修改订单状态 + 异步扣减真实库存(支付服务 + 订单服务 + 库存服务)

核心代码入口:

  • 下单冻结库存:com.tuling.tulingmall.ordercurr.service.impl.OmsPortalOrderServiceImpl#generateOrder
  • 支付后处理:com.tuling.tulingmall.ordercurr.service.impl.OmsPortalOrderServiceImpl#paySuccess

3. 常见解决方案对比

方案 一致性 吞吐量 实现复杂度 电商适用场景
2PC(Seata AT) 强一致性 下单冻结库存(强一致要求)
TCC 最终一致 无(电商少用,实现成本高)
可靠消息(RocketMQ) 最终一致 注册送优惠券、支付后扣库存(异步场景)
最大努力通知 最终一致 短信通知、日志推送(非核心数据)

面试结论 :电商项目核心采用Seata AT(2PC) 处理强一致同步场景,RocketMQ 事务消息 处理最终一致异步场景。

二、Seata 实现分布式事务

1. Seata 核心架构

(1)三大角色
  • TC(Transaction Coordinator) :事务协调者(独立部署的 Server 端),维护全局 / 分支事务状态,驱动提交 / 回滚(重要节点,标红
  • TM(Transaction Manager):事务管理器(嵌入应用的 Client 端),定义全局事务范围(开启 / 提交 / 回滚)
  • RM(Resource Manager):资源管理器(嵌入应用的 Client 端),管理本地资源,向 TC 注册分支事务、报告状态并执行提交 / 回滚
(2)分布式事务生命周期流程图

2. Seata 1.5.2 整合实战

(1)引入依赖
复制代码
<!-- 分布式事务seata依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <version>2.2.8.RELEASE</version>
    <exclusions>
        <exclusion>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.5.2</version>
</dependency>
(2)数据库初始化
复制代码
CREATE TABLE IF NOT EXISTS `undo_log` (
  `branch_id` BIGINT NOT NULL COMMENT 'branch transaction id',
  `xid` VARCHAR(128) NOT NULL COMMENT 'global transaction id',
  `context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
  `rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info',
  `log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status',
  `log_created` DATETIME(6) NOT NULL COMMENT 'create datetime',
  `log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime',
  UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';

注意:仅业务数据库需要建表,Seata Server 端无需建表。

(3)微服务 yml 配置(注册 / 配置中心为 Nacos)
复制代码
seata:
  application-id: tulingmall-product # 微服务应用名
  tx-service-group: tuling-order-group # 事务分组,与服务端vgroup_mapping后缀一致
  enable-auto-data-source-proxy: false # 分库分表场景需关闭自动代理
  registry:
    type: nacos
    nacos:
      application: seata-server
      server-addr: 192.168.65.103:8848
      group: SEATA_GROUP
  config:
    type: nacos
    nacos:
      server-addr: 192.168.65.103:8848
      namespace: 7e838c12-8554-4231-82d5-6d93573ddf32
      group: SEATA_GROUP
      data-id: seataServer.properties

关键注意 :Client 与 Server 的 Nacosnamespacegroup必须一致,否则无法通信。

3. 核心问题解决:Seata 整合 ShardingSphere 分库分表

(1)解决方案原理

将 Seata 的 DataSourceProxy 融入 ShardingSphere 的分片生态,由SeataATShardingTransactionManager统一管理事务,关闭 Seata 自动数据源代理,交给 Sharding-JDBC 处理。

(2)整合步骤
  1. 引入 ShardingSphere 整合 Seata 依赖

    <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-transaction-base-seata-at</artifactId> <version>4.1.1</version> </dependency>
  2. 配置 seata.conf(指定应用 ID 和事务分组)

    client {
    application.id = tulingmall-order-curr
    transaction.service.group = tuling-order-group
    }

  3. 替换事务注解(核心修改)

    // 禁用@GlobalTransactional,使用ShardingSphere的事务注解
    @ShardingTransactionType(TransactionType.BASE) // 基于Seata的柔性事务
    @Transactional
    public CommonResult generateOrder(OrderParam orderParam, Long memberId) {
    // 业务逻辑:创建订单+冻结库存
    }

三、可靠消息最终一致性方案(RocketMQ 事务消息)

1. 核心思想

事务发起方执行完本地事务后发送消息,消息消费方一定能接收并处理成功 ,强调最终数据一致性,适用于电商异步业务场景(如注册送优惠券、支付后扣库存)。

2. 本地消息表方案(基础版)

(1)方案原理

由 eBay 提出,通过本地事务保证业务操作和消息日志的一致性,再通过定时任务将消息发送至 MQ,确认消费成功后删除消息日志。

(2)注册送优惠券实战流程流程图
(3)核心要点
  • 本地事务:用户表和消息日志表在同一个本地事务中,保证原子性;
  • 定时任务:重试机制保证消息必发;
  • MQ ACK:消费方处理成功后发送 ACK,否则 MQ 重发;
  • 幂等性:消费方需实现幂等(如优惠券赠送需判断用户是否已领取),避免消息重发导致重复操作。

3. RocketMQ 事务消息(进阶版,电商主流)

(1)方案原理

RocketMQ 4.3 + 实现了完整的事务消息,将本地消息表封装到 MQ 内部 ,解决 Producer 端消息发送与本地事务执行的原子性问题 ;MQ Broker 作为事务协调者,通过双向通信 + 事务回查保证最终一致性。

(2)核心执行流程流程图
(3)核心特性:事务回查

当 Producer 执行本地事务时宕机 / 超时 ,MQ Server 会持续向同组的其他 Producer 节点发起事务回查 ,获取本地事务执行状态,根据结果决定是Commit 还是Rollback消息,保证消息不丢失、不重复。

(4)代码实现:实现 RocketMQLocalTransactionListener 接口
复制代码
public interface RocketMQLocalTransactionListener {
    /**
     * 发送Prepared消息成功后回调,执行本地事务
     * @param msg 消息(含transactionId唯一标识)
     * @param arg 发送消息时传递的参数
     * @return 事务状态:COMMIT/ROLLBACK/UNKNOWN
     */
    RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg);

    /**
     * MQ事务回查方法,判断本地事务执行状态
     * @param msg 消息
     * @return 事务状态:COMMIT/ROLLBACK/UNKNOWN
     */
    RocketMQLocalTransactionState checkLocalTransaction(Message msg);
}

返回值说明

  • COMMIT:MQ 标记消息可消费;
  • ROLLBACK:MQ 删除消息;
  • UNKNOWN:MQ 继续回查。
相关推荐
倚肆1 小时前
Spring WebSocket 核心注解详解
java·websocket·spring
重生之后端学习1 小时前
39. 组合总和
java·数据结构·算法·职场和发展·深度优先
QQ 31316378901 小时前
文华财经指标公式
java
毕设源码-赖学姐2 小时前
【开题答辩全过程】以 基于SpringBoot Vue的网络课程销售管理系统为例,包含答辩的问题和答案
java·spring boot·后端
Dylan的码园2 小时前
多线程的创建与管理
java·开发语言·多线程
玄〤2 小时前
个人博客网站搭建day3--Spring Boot JWT Token 认证配置的完整实现详解(漫画解析)
java·spring boot·后端·jwt
飞火流星020272 小时前
验证kafka队列中的数据是否是被压缩后的数据
分布式·kafka·验证kafka队列中的数据格式·验证kafka数据压缩·验证kafka数据是否已被压缩
Anastasiozzzz2 小时前
解决 RabbitMQ 的可靠性投递与消息重复消费问题思路
分布式·rabbitmq
马猴烧酒.2 小时前
【JAVA算法|hot100】堆类型题目详解笔记
java·开发语言·笔记