一、分布式事务基础概念
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 的 Nacosnamespace和group必须一致,否则无法通信。
3. 核心问题解决:Seata 整合 ShardingSphere 分库分表
(1)解决方案原理
将 Seata 的 DataSourceProxy 融入 ShardingSphere 的分片生态,由SeataATShardingTransactionManager统一管理事务,关闭 Seata 自动数据源代理,交给 Sharding-JDBC 处理。
(2)整合步骤
-
引入 ShardingSphere 整合 Seata 依赖
<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-transaction-base-seata-at</artifactId> <version>4.1.1</version> </dependency> -
配置 seata.conf(指定应用 ID 和事务分组)
client {
application.id = tulingmall-order-curr
transaction.service.group = tuling-order-group
} -
替换事务注解(核心修改)
// 禁用@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 继续回查。