分布式事务解决方案:最佳实践
开篇:什么是分布式事务?它用来做什么?

在开发大型系统时,我们经常会遇到一个难题:如何确保多个服务之间的数据一致性?
比如你在网上下单购买商品:
- 用户的账户服务要扣减余额
- 商品库存服务要减少库存
- 订单服务要记录订单信息
如果这三项操作分布在不同的服务中(也就是所谓的“微服务”架构),那么当其中某一项失败时,该如何保证其他两项也能“撤销”或“回滚”?这就引出了我们要讲的核心主题 —— 分布式事务。
一句话总结:
分布式事务是在多个系统、数据库或服务之间保持数据一致性的机制。
接下来,我们会一步步带你从零开始学习如何解决这个问题,并通过实际代码演示具体实现方案。
环境准备:搭建你的开发环境

为了能顺利运行示例项目,我们需要以下工具和环境配置:
必备工具清单:
| 工具 | 版本建议 | 下载地址 |
|---|---|---|
| JDK | 1.8+ | https://www.oracle.com/java/technologies/javase-downloads.html |
| Maven | 3.6+ | https://maven.apache.org/download.cgi |
| Spring Boot | 2.7.x | 自动管理 |
| MySQL | 5.7+ | https://dev.mysql.com/downloads/mysql/ |
| RabbitMQ / RocketMQ / Seata(我们使用Seata) | 最新版 | https://seata.io/zh-cn/docs/overview-download/ |
第一步:安装并配置MySQL

- 安装好 MySQL 服务。
- 创建三个数据库(模拟三个微服务中的数据库):
CREATE DATABASE order_service;
CREATE DATABASE account_service;
CREATE DATABASE inventory_service;
每个库中各建一张表,例如用户余额表:
USE account_service;
CREATE TABLE `account` (
`id` INT PRIMARY KEY,
`user_id` INT UNIQUE NOT NULL,
`balance` DECIMAL(10,2) DEFAULT 0.00
);
INSERT INTO account VALUES (1, 1001, 1000.00);
同样创建 order 和 inventory 表结构略过(完整示例见GitHub)
第二步:部署 Seata Server
- 下载 Seata Server(推荐使用 1.6.x)
- 解压后,修改配置文件
conf/file.conf,设置三数据库连接信息。 - 启动 Seata 服务:
sh seata-server.sh -p 8091 -h 127.0.0.1 -m file
✅ 提示:你可以使用 Docker 或直接解压运行。初学建议本地部署。
核心概念:通俗理解分布式事务的组成与机制

1. 什么是本地事务?
如果你只操作一个数据库,那可以用数据库自带的事务来保证 ACID 性质。比如:
@Transactional
public void transferMoney() {
deductFromAccount();
addIntoTargetAccount();
}
只要这两个操作在一个数据库中,就可以用事务控制成功或失败全部回滚。
2. 那么为什么需要“分布式”事务?
当你的业务逻辑分布在多个数据库或服务上,传统本地事务就无能为力了。这时候就需要分布式事务框架来帮你协调。
3. 常见的分布式事务方案有哪些?
| 方案名称 | 是否需要引入额外组件 | 强一致性? | 可用性高吗? | 场景举例 |
|---|---|---|---|---|
| 两阶段提交(2PC) | 是 | ✅ 是 | ❌ 较差 | 银行转账等强一致性场景 |
| TCC补偿机制 | 否 | ✅ 是 | ✅ 高 | 支付交易、库存扣减 |
| Saga 模式 | 否 | ❌ 否 | ✅ 高 | 复杂流程处理 |
| 消息队列最终一致 | 否 | ❌ 否 | ✅ 很高 | 日志、通知类 |
| Seata(支持AT、TCC、Saga) | 是 | ✅ | ✅ | 推荐通用方案 |
今天我们要使用的,就是 阿里巴巴开源的 Seata,它支持自动化的 AT 模式,非常适合入门。
实战项目:跟着教程一步步写一个分布式事务示例

我们设计一个简单的业务场景:用户下单 → 扣库存 + 减余额 → 创建订单。
我们将构建三个 Spring Boot 应用,分别对应:
- Account Service(账户服务)→ 减余额
- Inventory Service(库存服务)→ 减库存
- Order Service(订单服务)→ 生成订单
步骤 1:创建 Spring Boot 工程
以 IntelliJ IDEA 为例:
新建 Maven Project,选择 Spring Initializr,添加依赖:
- Spring Web
- MyBatis
- Spring Data JPA(可选)
- Seata Starter(Spring Boot 中添加如下依赖):
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.6.1</version>
</dependency>
步骤 2:每个服务注册 Seata Client
在 application.yml 添加如下配置:
seata:
enabled: true
application-id: account-service
tx-service-group: my_test_tx_group
✅ 注意:所有服务中的
tx-service-group要一致!
步骤 3:编写调用链入口(Order Service)
在 OrderController 中添加下单接口:
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private AccountClient accountClient;
@Autowired
private InventoryClient inventoryClient;
@GlobalTransactional // 关键注解!开启全局事务
public ResponseEntity<String> createOrder() {
accountClient.deductBalance(1001, 100);
inventoryClient.reduceStock(2001, 1);
// 插入订单逻辑...
return ResponseEntity.ok("Order created!");
}
}
⚠️ 注意:@GlobalTransactional 是 Seata 提供的注解,用于声明这是一个全局事务入口点。
步骤 4:远程调用加 Feign
使用 Spring Cloud OpenFeign 实现跨服务调用:
@FeignClient(name = "account-service")
public interface AccountClient {
@PostMapping("/deduct")
ResponseEntity<String> deductBalance(@RequestParam int userId, @RequestParam double amount);
}
其他服务同理配置 Feign。
步骤 5:验证失败情况下的事务一致性
可以在任意一个方法中抛异常,比如:
if (stock <= 0) {
throw new RuntimeException("库存不足");
}
这时整个事务会回滚,余额不会被扣除,库存也不会减少。
常见问题:新手最容易卡住的地方在这里!

Q1:启动应用时报错“找不到 RM 信息”怎么办?
✅ 答:确认你已正确配置 file.conf 和 registry.conf,并将数据库信息填入。Seata client 会自动向 server 注册资源管理器(RM)。
Q2:用了 @GlobalTransactional 却不生效?
✅ 答:确保你在主类添加了 @EnableFeignClients,并且远程调用是通过 Feign、Dubbo 或 REST Template 完成的。否则 Seata 无法拦截请求。
Q3:Seata 事务日志在哪看?
✅ 答:查看 logs/seata.log 文件,Seata 默认会在 logs 目录输出详细事务执行过程。
学习建议:下一步怎么进阶?
恭喜你完成了本次实战演练!
如果你想进一步深入这个领域,可以沿着这些方向继续学习:
1. 学习更多分布式事务模式
- 理解 TCC 的原理和实现方式
- 尝试使用 RocketMQ 的事务消息机制
- 学习 Saga 模式的应用场景
2. 探索更复杂的事务模型
- 结合事件驱动架构(Event-driven)
- 使用 Saga 模式 + 补偿机制做长周期任务处理
3. 学习微服务治理相关知识
- 熟悉 CAP 定理与 BASE 思想
- 了解熔断限流、负载均衡等基础知识
4. 动手做个综合项目
比如开发一个“电商后台系统”,包含:
- 商品模块
- 库存模块
- 订单模块
- 支付模块 尝试将它们全部连接起来,用 Seata 实现一致性控制。
写在最后
分布式事务并不是一蹴而就的技术,它是你从单体应用走向大型系统的关键桥梁。
希望这篇教程能为你打开一扇门。记住一句话:
“先实现再优化,先理解再扩展。”
持续编码、多思考、敢实验,你一定能成为分布式系统设计高手!
附录:完整项目代码参考
👉 GitHub 示例仓库(自行补充实际链接)
👉 Seata 官方文档:https://seata.io/zh-cn/docs/
如需进一步交流,请留言提问。祝你学习愉快,早日写出漂亮的分布式系统!

评论 0