分布式事务解决方案:最佳实践(新手友好版)
开篇:什么是分布式事务?为什么要学它?

在开发大型系统时,我们经常需要操作多个数据库或服务。例如:
- 用户下单购买商品时,可能需要同时修改订单数据库和库存数据库。
- 银行转账时,需要从一个账户扣钱,再给另一个账户加钱。
这些操作如果其中一步失败,整个流程都应该失败,否则数据就会出错。这,就是“事务”要解决的问题。
传统的单数据库应用中,我们使用 本地事务(Local Transaction),比如 SQL 中的 BEGIN TRANSACTION 和 COMMIT/ROLLBACK。
但在微服务架构中,各个模块独立运行、访问各自的数据源,这就需要处理跨服务的事务一致性。这种情况下,我们称之为 分布式事务(Distributed Transaction)。
分布式事务的关键点是:
- 多个服务参与
- 数据变更必须全部成功或者全部失败(具备 ACID 属性中的原子性和一致性)
- 要保证数据最终一致
本教程将带你一步步了解分布式事务的核心概念,并通过代码示例实现一个简单的场景。
环境准备:搭建我们的开发环境


你需要安装以下工具(以 Java 技术栈为例):
1. JDK 17(或其他 LTS 版本)
你可以去官网下载:https://adoptium.net
验证命令:
java -version
2. Maven 构建工具
Maven 是 Java 的标准项目构建工具。
下载地址:https://maven.apache.org/download.cgi
验证命令:
mvn -v
3. Spring Boot(推荐版本 3.x)
我们将基于 Spring Boot 构建微服务。
Spring Initializr 地址:
https://start.spring.io
选择如下选项:
- Project: Maven
- Language: Java
- Spring Boot Version: 最新稳定版
- Dependencies: Spring Web, Spring Data JPA, Lombok(可选)
生成后下载项目解压即可。
4. MySQL 或 PostgreSQL 数据库
我们用两个数据库模拟两个不同的服务。
MySQL 安装指南:
https://dev.mysql.com/doc/refman/8.0/en/installing.html
创建两个数据库示例:
CREATE DATABASE order_service;
CREATE DATABASE inventory_service;
5. IDE(建议 IntelliJ IDEA 或 VS Code)
核心概念:通俗解释分布式事务相关术语

这一部分我们将用最简单易懂的语言,介绍几个核心概念。
1. 分布式事务 vs 本地事务
| 类型 | 描述 |
|---|---|
| 本地事务 | 在单一数据库或服务内执行 |
| 分布式事务 | 涉及多个服务之间的数据操作协调 |
📝 举个例子:你在家洗衣服是本地事务;但如果你还要一边洗衣服一边煮饭,这就是分布式任务了。
2. CAP 定理(理解基本思想)
CAP 是分布式系统的经典理论之一,指的是:
- C:Consistency(一致性)
- A:Availability(可用性)
- P:Partition tolerance(分区容忍)
这三个只能同时满足两个。
在设计分布式系统时,通常会牺牲一致性来换取高可用和容错能力。
3. 常见的分布式事务解决方案
以下是几种主流方案:
| 方案名称 | 适用场景 | 优缺点 |
|---|---|---|
| 两阶段提交(2PC) | 强一致性要求高的场景 | 可靠但性能差,依赖中心节点(协调者) |
| TCC(Try-Confirm-Cancel) | 对业务逻辑有一定控制力 | 实现复杂,适合金融类系统 |
| Saga 模式 | 长周期、异步处理任务 | 易实现但需处理回滚逻辑 |
| 事件驱动 + 最终一致性 | 松耦合、高并发场景 | 异步处理,延迟小,但不能保证强一致 |
| Seata(阿里开源框架) | 快速上手 | 支持多种模式,社区活跃 |
我们在实战项目中将重点演示 Seata 的使用,因为它是目前企业级较为流行的开源解决方案之一。
实战项目:用 Seata 实现订单 + 库存减扣的分布式事务
我们模拟这样一个场景:
- 用户下订单,需要操作两个服务:
- OrderService:下单并记录订单信息
- InventoryService:减少商品库存
- 如果其中一个步骤失败,整个操作都要回滚
第一步:创建两个 Spring Boot 项目
1. 创建 OrderService 项目
使用 Start.Spring.IO 添加如下依赖:
- Spring Web
- Spring Data JPA
- Lombok(可选)
配置 application.yml 文件连接到 order_service 数据库
2. 创建 InventoryService 项目
类似地创建第二个项目,连接到 inventory_service 数据库
第二步:引入 Seata 客户端
在两个项目的 pom.xml 中添加 Seata 依赖:
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>最新版如 1.6.1</version>
</dependency>
配置 application.yml 加入 Seata 客户端配置:
seata:
enabled: true
application-id: order-service # 不同的服务名
tx-service-group: my_test_tx_group
service:
vgroup-mapping:
my_test_tx_group: default
grouplist:
default: 127.0.0.1:8091
config:
type: file
registry:
type: file
第三步:启动 Seata Server(TC 组件)
Seata 的架构包括三个组件:
- TC(Transaction Coordinator):负责协调全局事务
- TM(Transaction Manager):发起方
- RM(Resource Manager):参与者(每个数据库)
你可以在官方 GitHub 下载并启动 TC Server: https://github.com/seata/seata/releases
进入目录执行启动脚本:
sh seata-server.sh -p 8091 -m file
第四步:编写核心业务逻辑
1. OrderController.java(OrderService 中)
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping("/order")
public String createOrder(@RequestParam("productId") Long productId) {
try {
orderService.createOrder(productId);
return "下单成功";
} catch (Exception e) {
return "下单失败:" + e.getMessage();
}
}
}
2. OrderService.java
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private InventoryClient inventoryClient;
@GlobalTransactional // Seata 标记开启分布式事务
public void createOrder(Long productId) {
// 1. 创建订单
Order order = new Order();
order.setProductId(productId);
order.setStatus("CREATED");
orderRepository.save(order);
// 2. 扣除库存(调用远程接口)
String result = inventoryClient.decreaseInventory(productId, 1L);
if (!"SUCCESS".equals(result)) {
throw new RuntimeException("库存扣除失败");
}
}
}
3. InventoryService 提供 REST API
@RestController
@RequestMapping("/inventory")
public class InventoryController {
@PostMapping("/decrease")
public String decreaseInventory(@RequestParam("productId") Long productId,
@RequestParam("count") Long count) {
// 这里简化模拟实际操作
boolean success = inventoryService.decreaseStock(productId, count);
return success ? "SUCCESS" : "FAILURE";
}
}
第五步:测试一下!
启动 Seata Server → 启动两个服务 → 发起请求:
POST http://localhost:8080/order?productId=1
这时如果任何一方失败(比如库存不足),整个事务都会回滚,订单不会保存。
常见问题解答
问题1:为什么我看到本地事务还在,但数据没回滚?
答:确保:
- Seata Server 正常运行
@GlobalTransactional注解已正确添加- 项目中引入了正确的依赖(特别是数据库代理)
问题2:我的服务没有使用数据库怎么办?
答:如果你只是远程调用外部系统,TCC 或 Saga 模式更适合。Seata 也支持此类集成。
问题3:可以不用 Seata 吗?
答:当然可以!如果你希望更轻量级的方式,可以选择:
- 基于消息队列的事件驱动
- 使用 RocketMQ、RabbitMQ 等结合补偿机制实现最终一致
学习建议:接下来怎么深入学习?
初学者进阶路线图:
✅ 第一阶段(基础掌握)
- 完成本文实战项目
- 学习 Seata 的其他模式(AT、TCC、SAGA)
- 理解注册中心与配置中心的作用(Nacos、Eureka)
✅ 第二阶段(深度理解)
- 学习 CAP、BASE 理论
- 掌握 TCC 模式下的 Try、Confirm、Cancel 三种方法
- 尝试自定义分布式事务管理器
✅ 第三阶段(生产实践)
- 结合 Kafka/RocketMQ 实现事件驱动型事务
- 探索分布式事务与微服务治理的融合
- 研究 DTM、Apache ServiceCombSaga 等替代方案
总结

分布式事务虽然听起来很复杂,但实际上它是在帮助我们在微服务架构下安全地操作数据。本文通过通俗讲解 + 实战案例的形式,引导你初步掌握了分布式事务的基本概念和使用方式。
只要你愿意多练习,理解每种模型背后的原理,很快就能掌握这项重要技能。记住一句话:
“事务不是用来保证成功的,而是为了在失败时能够优雅回退。”
继续加油,未来你也可以轻松应对高并发、大规模系统的挑战!
🔍 延伸资源推荐:
- Seata 官网文档:https://seata.io/zh-cn/docs/overview/what-is-seata/
- Spring Cloud Alibaba 整合教程
- 《Java 高并发编程实战》书籍(含分布式章节)

评论 0