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

在我们学习编程的时候,很多同学都写过类似“银行转账”的程序。比如:
- 用户A给用户B转账100元
- 系统先从A的账户中扣掉100元
- 再往B的账户中加100元
这看起来很简单对吧?但你知道吗,这个过程如果是在一个系统里完成的,数据库会保证这两个操作要么都成功,要么都不执行 —— 这就是本地事务。
但随着项目变大,我们通常会把不同的功能拆成多个微服务:
- 账户服务(管理余额)
- 订单服务(管理订单状态)
- 库存服务(管理商品库存)
这个时候问题就来了:
如果A下单买了东西,需要同时减少库存和创建订单。可如果减库存成功了,但订单没创建成功怎么办?
这种跨服务、跨数据库的数据一致性问题,就是我们要解决的分布式事务问题。
本教程将带你从零开始,一步步掌握最实用的分布式事务解决方案!
环境准备:搭建开发环境

所需软件与工具:
| 工具 | 用途 |
|---|---|
| JDK 1.8+ | Java运行环境 |
| Spring Boot 2.7+ | 快速搭建后端服务 |
| MySQL 5.7+ 或 MariaDB | 数据库存储 |
| Docker | 容易部署 Seata Server |
| Maven | 构建项目依赖 |
| IntelliJ IDEA / VS Code | 编辑器 |
步骤一:安装Java和Spring Boot
建议使用 Spring Initializr 创建项目骨架,选中:
- Web
- Data JPA
- MySQL Driver
下载并用IDE打开。
步骤二:配置数据库
spring:
datasource:
url: jdbc:mysql://localhost:3306/your_db
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
步骤三:启动Seata服务器(用于后面的AT模式)
使用Docker快速启动Seata Server:
docker run --name seata-server -p 8091:8091 seataio/seata-server:v1.5.2
你也可以去官网下载手动安装:https://seata.apache.org/zh-cn/docs/quick-start/
核心概念:什么是分布式事务?
举个通俗例子
想象你在超市里买东西:
- 收银员告诉你价格是50元 ✅
- 你扫码付款成功 ✅
- 结账后,打印机卡住没出票 ❌
这时候你会怎么想?肯定是:“我明明付钱了,为啥没票?” 这个时候就需要系统来处理这个问题了 —— 这就是我们需要处理的数据不一致问题。
关键词解释:
| 概念 | 含义 |
|---|---|
| 事务 | 一组连续的操作,要么全部成功,要么全部失败 |
| 本地事务 | 在单一数据库上使用的事务机制 |
| 分布式事务 | 跨多个服务或数据库的数据一致性控制机制 |
| CAP定理 | 一致性、可用性、分区容忍性三者不能兼顾 |
| 最终一致性 | 不强制要求立即一致,只要求最后达到一致即可 |
四种常见方案对比
| 方案名称 | 是否强一致 | 适用场景 | 实现难度 |
|---|---|---|---|
| 本地消息表 | ✅ 最终一致 | 小型项目、弱一致性 | 简单 |
| TCC | ✅ 需要自己实现补偿逻辑 | 中大型电商、支付系统 | 中等偏难 |
| Saga | ❌ 可能中间态不一致 | 长周期任务如物流流程 | 中等 |
| AT(Seata) | ✅ 强一致 | 微服务架构通用 | 较简单 |
我们将重点学习其中最常用且较简单的两种:
- TCC(Try-Confirm-Cancel)
- AT模式(基于Seata)
实战项目:做一个“下单减库存”小项目

项目结构如下:
.
├── order-service # 下单服务
├── inventory-service # 库存服务
└── account-service # 账户服务(后面扩展用)
第一步:定义接口
我们在两个服务之间通过 OpenFeign 调用:
// InventoryService.java(库存服务接口)
public interface InventoryService {
boolean decreaseStock(String productId, int count);
}
// OrderService.java(订单服务接口)
public interface OrderService {
boolean createOrder(String userId, String productId, int count);
}
第二步:模拟下单流程(不考虑事务时)
// OrderServiceImpl.java
public boolean createOrder(String userId, String productId, int count) {
// 1. 减库存
boolean reduce = inventoryService.decreaseStock(productId, count);
if (!reduce) return false;
// 2. 创建订单
Order order = new Order(userId, productId, count);
orderRepository.save(order);
return true;
}
⚠️ 但如果创建订单失败呢?库存就被错误地减少了!
这就是典型的分布式事务问题!
解决方案一:TCC(Try-Confirm-Cancel)
什么是TCC?
TCC 是一种常见的分布式事务方案,核心思想是:
- Try:尝试执行,资源预留(冻结库存)
- Confirm:确认执行,真正扣减资源(正式减库存)
- Cancel:取消执行,释放资源(回滚冻结)
示例:下单 + 减库存 TCC 流程
1. 先冻结库存(Try)
// InventoryService.java
@Transactional
public boolean tryFreezeStock(String productId, int count) {
int currentStock = stockDao.getStock(productId);
if (currentStock < count) return false;
// 冻结库存(增加 frozen_stock 字段)
stockDao.updateFrozenStock(productId, count);
return true;
}
2. 确认减库存(Confirm)
@Transactional
public void confirmReduceStock(String productId, int count) {
stockDao.reduceStock(productId, count);
}
3. 回滚冻结库存(Cancel)
@Transactional
public void cancelFreezeStock(String productId, int count) {
stockDao.cancelFrozenStock(productId, count);
}
4. 订单服务调用流程(伪代码)
String transactionId = UUID.randomUUID().toString();
try {
// Step 1: 尝试冻结库存
boolean frozen = inventoryService.tryFreezeStock("product1", 1);
// Step 2: 创建订单
orderRepository.save(new Order(...));
// Step 3: 确认减库存
inventoryService.confirmReduceStock("product1", 1);
} catch (Exception e) {
// Step 4: 失败时回滚冻结
inventoryService.cancelFreezeStock("product1", 1);
}
✅ 这样就能确保“要么都成功,要么都失败”。
解决方案二:使用 Seata 的 AT 模式(推荐初学者)
什么是 Seata?什么是 AT 模式?
Seata 是阿里巴巴开源的一个分布式事务框架。
AT(Auto Transaction)模式的特点是:
- 自动提交事务
- 透明化对业务无侵入
- 使用全局事务ID协调多个服务的一致性
步骤一:添加Seata依赖(以order-service为例)
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.5.2</version>
</dependency>
步骤二:配置Seata客户端
seata:
enabled: true
application-id: order-service
tx-service-group: my_tx_group
registry:
type: nacos
nacos:
server-addr: 127.0.0.1:8848
记得也配置 inventory-service 和 account-service。
步骤三:开启全局事务注解
@GlobalTransactional(name = "create-order-tx")
public boolean createOrderWithTx(String userId, String productId, int count) {
boolean success = inventoryService.reduceStock(productId, count);
if (!success) return false;
orderRepository.save(new Order(...));
return true;
}
这样,Seata就会自动帮你处理事务一致性啦!
常见问题解答(Q&A)
Q1:为什么我的订单创建成功但库存没扣?
可能是网络延迟或调用失败导致部分服务未执行完。请检查日志是否出现异常,并确认你的事务是否完整包裹所有关键操作。
Q2:TCC太复杂,适合初学者吗?
TCC适合理解原理,适合有经验后做定制化逻辑。如果是初学者,建议从Seata入手,它更简单也更适合生产。
Q3:Seata一定要配合数据库吗?
是的,Seata需要修改数据库表,添加 undo_log 表来记录事务日志。可以自动生成,具体参考官方文档。
Q4:TCC和Seata哪个更好?
- TCC 更灵活,但要自己实现三个步骤,适合有特定需求的系统。
- Seata AT 对业务代码几乎无侵入,适合大多数项目。
学习建议:下一步学什么?
恭喜你完成了分布式事务的基础学习!接下来你可以继续探索以下内容:
推荐进阶方向:
| 主题 | 推荐学习内容 |
|---|---|
| 消息队列 | Kafka、RocketMQ(可用于实现最终一致性的本地消息表) |
| 分布式锁 | Redis分布式锁、Zookeeper |
| 分库分表 | ShardingSphere、MyCat |
| 事件溯源(Event Sourcing) | CQRS+Event Store 架构 |
| 领域驱动设计(DDD) | 更好组织复杂业务模型 |
推荐书籍与资料:
- 《深入理解分布式事务》
- 《企业IT架构转型之道》
- Seata官方文档
- GitHub开源项目实战案例
总结
通过本教程你已经掌握了:
✅ 分布式事务的基本概念
✅ 如何搭建开发环境
✅ 使用 TCC 实现自定义分布式事务
✅ 使用 Seata 实现自动化事务控制
✅ 新手常见问题的解答方法
如果你是从零基础开始的,现在你已经拥有了构建中大型项目的底气!
继续加油,在成为后端高手的路上越走越远!🌟
📌 友情提示: 如果你能坚持做完项目示例、看懂每一个代码片段,并尝试用自己的语言复述出来,你就真的掌握了这项技能。欢迎动手实践!

评论 0