在 Java 开发中,分布式事务是指跨越多个数据库、服务或微服务节点的事务操作,这些操作要么全部成功,要么全部失败,保持一致性(ACID原则的一致性和原子性),就像本地事务一样。
🔹一、为什么需要分布式事务?
当系统从单体架构演化为微服务架构或分布式架构,一个业务操作可能涉及:
- 多个数据库(如订单库、库存库)
- 多个微服务(如订单服务、支付服务、物流服务)
- 多种存储系统(如关系型数据库 + 消息队列)
这时一个操作无法用传统的本地事务(例如 JDBC 事务)来保证整体一致性,因此需要分布式事务机制。
🔹二、常见的分布式事务场景
业务场景 | 涉及系统 |
---|---|
下单流程 | 订单服务、库存服务、账户服务 |
支付成功后发货 | 支付系统、物流系统 |
微服务调用链 | A服务调用B,B调用C,事务需统一回滚 |
🔹三、解决方案类型
1. 两阶段提交(2PC,XA协议)
✅ 特点:
- 保证强一致性
- 使用数据库的 XA 事务支持(如 MySQL InnoDB + Atomikos)
❌ 缺点:
- 性能差、资源锁定严重
- 数据库耦合度高,不适合高并发业务场景
2. 本地消息表 + 事务消息(可靠消息最终一致性)
如阿里巴巴提出的 TCC / 消息驱动 模式:
示例流程:
- 业务服务写入本地消息表 + 本地数据库事务提交(同一个本地事务)
- 消息服务异步投递 MQ 消息
- 下游服务接收消息并执行操作
✅ 优点:
- 高性能
- 最终一致性
✅ 中间件代表:
- RocketMQ 的事务消息
- Kafka 的 exactly-once
- RabbitMQ 手动 ack + 重试机制
3. TCC 模型(Try-Confirm-Cancel)
每个服务实现三个接口:
-
Try
: 预留资源 -
Confirm
: 确认操作 -
Cancel
: 回滚操作
适合业务粒度明确的操作,例如:支付扣款、库存锁定
✅ 优点:
- 性能好,适合强一致性要求
- 控制力强,可按业务自定义补偿
❌ 缺点:
- 开发复杂,服务需实现三段逻辑
4. SAGA 模型(长事务 + 补偿)
Saga 是由一系列本地事务组成,每个本地事务执行后,若失败则依次执行补偿事务进行回滚。
适用场景:
- 长事务、订单流程(下单、锁库存、扣余额)
常用工具:
- Apache ServiceComb Saga
- Netflix Conductor
- Seata 的 Saga 模式
🔹四、分布式事务中间件推荐(Java 生态)
中间件 | 特点 |
---|---|
Seata (阿里) | 支持 AT / TCC / SAGA / XA 模式 |
LCN(Jdchain) | 支持基于数据库的分布式事务 |
Hmily | 高性能的 TCC 实现 |
Atomikos | 老牌 Java 分布式事务管理器,支持 XA |
RocketMQ事务消息 | 基于 MQ 的事务一致性 |
Canal + 消息队列 | 异步最终一致性方案 |
🔹五、总结:不同事务模型对比
模型 | 一致性 | 性能 | 应用复杂度 | 场景 |
---|---|---|---|---|
XA(2PC) | 强一致 | 差 | 简单 | 银行、转账等高要求一致性 |
TCC | 强一致 | 高 | 高 | 支付、扣库存、下单等 |
SAGA | 最终一致 | 高 | 中等 | 电商业务流程 |
可靠消息 | 最终一致 | 高 | 中等 | 微服务调用链 |
如果你是面试时被问:
❓面试官:如何保证分布式事务一致性?
你可以答:
分布式事务的一致性可以通过 Seata、TCC 模式或本地消息表 + MQ 实现。在业务允许最终一致性的情况下,我们通常采用异步消息 +幂等 + 重试机制提高性能和可用性;若业务要求强一致,可选择 TCC 或 XA 协议。
Seata 是阿里开源的 分布式事务解决方案,支持 AT、TCC、SAGA 和 XA 四种事务模式,尤其适合 Spring Cloud / Spring Boot / Dubbo / Nacos 等微服务环境。
✅ 一、Seata 使用场景(以 AT 模式为例)
假设有一个电商系统,下单流程需要跨越以下 3 个微服务:
- 订单服务:写入订单表
- 库存服务:扣减库存
- 账户服务:扣减用户余额
我们希望这三步要么全部成功,要么全部失败,Seata 就能帮我们实现这个分布式事务一致性。
🧰 二、Seata 快速使用(Spring Boot + MySQL 示例)
1️⃣ 环境准备
- JDK 8+
- Spring Boot 项目(多个微服务模块)
- 数据库:MySQL 5.7+(需支持 undo log)
- 注册中心(如:Nacos)
- 下载并启动 Seata Server:https://github.com/seata/seata/releases
2️⃣ 数据库改造(重要)
每个微服务的业务表必须满足:
- 表必须有主键
- 每个库都加
undo_log
表(用于事务回滚)
CREATE TABLE `undo_log` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`branch_id` BIGINT(20) NOT NULL,
`xid` VARCHAR(100) NOT NULL,
`context` VARCHAR(128) NOT NULL,
`rollback_info` LONGBLOB NOT NULL,
`log_status` INT(11) NOT NULL,
`log_created` DATETIME NOT NULL,
`log_modified` DATETIME NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB;
3️⃣ 引入依赖(示例:Spring Boot)
<!-- seata 依赖 -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.7.1</version> <!-- 推荐和 seata-server 同版本 -->
</dependency>
4️⃣ 配置 application.yml(微服务)
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
datasource:
url: jdbc:mysql://localhost:3306/order_db
username: root
password: root
seata:
enabled: true
application-id: order-service
tx-service-group: my_tx_group
service:
vgroup-mapping:
my_tx_group: default
grouplist:
default: 127.0.0.1:8091
data-source-proxy-mode: AT
注意:
tx-service-group
是事务组名,用于注册全局事务协调器vgroup-mapping
是事务组和 Seata Server 实例的映射
5️⃣ 编写代码
在业务入口标注 @GlobalTransactional
@RestController
@RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
@PostMapping("/order/create")
@GlobalTransactional(name = "create-order-tx", rollbackFor = Exception.class)
public String createOrder(@RequestBody OrderDto dto) {
orderService.createOrder(dto);
return "success";
}
}
各个服务方法使用本地事务(@Transactional
)
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private InventoryClient inventoryClient;
@Transactional
public void createOrder(OrderDto dto) {
orderMapper.insert(dto.toEntity());
inventoryClient.decreaseStock(dto.getProductId(), dto.getAmount());
// throw new RuntimeException("模拟异常"); // 会全局回滚
}
}
Seata 会通过代理数据源和 undo_log 自动实现本地事务的回滚
✅ 三、关键点总结
步骤 | 必做事项 |
---|---|
🧱 数据库 | 所有表都必须有主键,并加 undo_log 表 |
⚙ 配置 | 每个服务都要配置 Seata 的 group、注册中心等 |
💾 数据源代理 | Seata 会自动代理 Druid / HikariCP 数据源 |
🔁 全局事务注解 |
@GlobalTransactional 只能加在入口方法上 |
📦 Seata Server | 需要启动并注册到 Nacos(或其他) |
✅ 四、常见问题排查
问题 | 原因 |
---|---|
事务不生效 | 忘记使用 @GlobalTransactional
|
回滚失败 | 表无主键或无 undo_log 表 |
数据未代理 | 未启用 seata 的数据源代理模式 |
服务不注册 | Nacos 未配置 / group 映射未设置 |
✅ 五、进阶推荐
- 模式切换:Seata 支持 AT / TCC / SAGA 等,可灵活选择
- 与 Dubbo、Feign、RocketMQ 整合
- 二阶段事务失败补偿机制
- 分布式锁 + 幂等性控制配套
Top comments (0)