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

在传统的单体架构中,数据库事务非常好处理。比如一个银行转账操作:“从A账户减钱”和“给B账户加钱”可以放在同一个事务里,要么一起成功,要么一起失败。
但是在现代系统中,尤其是微服务架构中,业务被拆分到多个服务里,例如:
- 用户服务负责用户信息
- 订单服务负责下单
- 库存服务负责扣库存
- 支付服务负责支付
这些服务各自使用不同的数据库,那么如果出现一个操作需要跨服务执行(比如下单时同时扣库存、生成订单),就无法再通过单个事务来保证数据一致性了。
这就是我们今天要讲的主题——分布式事务。
一句话总结:当多个服务或数据库参与一个操作的时候,如何让它们像一个整体一样工作?这就要用到分布式事务解决方案。
环境准备:搭建你的第一个分布式项目环境

我们要写的是一个最简单的电商项目示例:用户下单 + 扣库存,涉及到两个服务:
order-service负责创建订单inventory-service负责减少库存
技术栈(简单易上手):
- Java 17
- Spring Boot 3.x
- MySQL 8
- Lombok
- Seata(开源的分布式事务框架)
步骤一:安装JDK & Maven
请自行下载安装好 JDK 17 和 Maven,并配置好环境变量。
步骤二:安装MySQL并建库
创建两个数据库分别模拟两个服务的数据存储:
-- 创建 order 数据库
CREATE DATABASE order_db;
-- 创建 inventory 数据库
CREATE DATABASE inventory_db;
然后在这两个数据库下建立对应的表:
order_db.order_table:
CREATE TABLE order_table (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
product_id BIGINT NOT NULL,
count INT NOT NULL
);
inventory_db.inventory_table:
CREATE TABLE inventory_table (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
product_id BIGINT UNIQUE NOT NULL,
stock INT NOT NULL DEFAULT 0
);
插入一条测试商品:
INSERT INTO inventory_db.inventory_table (product_id, stock) VALUES (1001, 10);
步骤三:启动 Seata Server
Seata 是实现分布式事务的一个开源中间件,它作为协调者帮助我们管理全局事务。
安装步骤简述:
- 前往 Seata GitHub 下载最新 release 包。
- 解压后进入目录:
cd seata-server-xx.x.x - 启动 TC(Transaction Coordinator):
sh seata-server.sh -p 8091 -m db
默认使用的是 file 模式,我们也可以改成数据库模式以便持久化保存事务日志。
核心概念讲解
下面是一些你需要了解的关键术语:
| 概念名称 | 中文解释 | 简单理解 |
|---|---|---|
| XA协议 | 一种经典分布式事务协议 | 多个数据库支持它,但性能差 |
| TCC | Try-Confirm-Cancel | 先预占资源,再确认或回滚 |
| Saga | 补偿型事务 | 一步一步执行,失败则反向补偿 |
| SAGA与TCC的区别 | 实现方式不同 | TCC强调预占,Saga强调补偿 |
| Seata | 阿里开源的分布式事务框架 | 提供一站式解决方案 |
我们选用Seata + AT模式进行实战演示:
AT模式优势:对业务无侵入,兼容性好,适合刚接触分布式事务的新手。
实战项目:写一个分布式事务案例
我们现在要做一个功能:用户下单的时候自动扣除对应商品库存,整个过程必须具备事务能力。
项目结构概览
我们将构建两个 Spring Boot 微服务:
order-serviceinventory-service
每个服务都有独立的数据库。
第一步:添加 Seata 的依赖(以 Maven 为例)
在两个项目的 pom.xml 中加入:
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.6.1</version>
</dependency>
第二步:配置 Seata 客户端
在每个微服务的 application.yml 文件中添加如下配置:
seata:
enabled: true
application-id: order-service # 或 inventory-service
tx-service-group: default_tx_group
service:
vgroup-mapping:
default_tx_group: default
grouplist:
default: 127.0.0.1:8091
config:
type: file
registry:
type: file
确保两个服务都能找到 Seata Server。
第三步:编写下单接口
在 OrderService 中调用 InventoryFeignClient 来扣库存:
// OrderController.java
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping("/place-order")
public String placeOrder(@RequestBody OrderDTO dto) {
try {
orderService.createOrder(dto);
return "下单成功!";
} catch (Exception e) {
return "下单失败:" + e.getMessage();
}
}
}
实现核心逻辑(伪代码):
@Transactional
public void createOrder(OrderDTO dto) throws Exception {
// 1. 创建订单记录
jdbcTemplate.update("INSERT INTO order_table(user_id, product_id, count) VALUES(?,?,?)",
dto.getUserId(), dto.getProductId(), dto.getCount());
// 2. 调用库存服务,扣库存
inventoryFeignClient.decreaseStock(dto.getProductId(), dto.getCount());
}
第四步:在库存服务中定义扣库存方法
@FeignClient(name = "inventory-service")
public interface InventoryFeignClient {
@PostMapping("/decrease-stock")
void decreaseStock(@RequestParam Long productId, @RequestParam Integer count);
}
@RestController
public class InventoryController {
@Transactional
@PostMapping("/decrease-stock")
public void decreaseStock(@RequestParam Long productId, @RequestParam Integer count) {
int currentStock = getCurrentStock(productId);
if (currentStock < count) {
throw new RuntimeException("库存不足!");
}
// 更新库存
jdbcTemplate.update("UPDATE inventory_table SET stock = stock - ? WHERE product_id = ?",
count, productId);
}
}
第五步:测试异常场景
你可以故意在某个服务中抛出异常,观察是否能回滚。
比如修改 InventoryController 中的代码:
throw new RuntimeException("人为制造错误");
再次调用 /place-order 接口,观察订单有没有被创建、库存有没有被减少。
如果没有变化,说明 Seata 正确地进行了事务回滚!
新手常见问题解答
Q1:为什么Seata启动不起来?
- 可能没有开放端口;
- 可能配置文件路径不对;
- 使用数据库模式的话,需要额外配置数据库连接信息。
Q2:我在一个服务中开启@Transactional,另一个服务报错会回滚吗?
✅ 如果你使用了 Seata 并且正确配置,是可以的。
❌ 如果你没有集成任何分布式事务框架,这是做不到的。
Q3:除了Seata还有其他替代方案吗?
当然有:
- Atomikos(两阶段提交实现)
- Nacos + RocketMQ 实现异步事务消息
- 自研 TCC 框架等
但对于新手来说,Seata是最好的入门选择之一。
学习建议:下一步怎么深入学习?
✅ 初学完成推荐路线如下:
- 理解 Seata 支持的其他模式(如TCC、SAGA)及其适用场景
- 动手实现一个基于事件驱动+本地事务表的“最终一致性”方案
- 学习 Kafka 或 RocketMQ 的事务消息机制
- 掌握 CAP 原则,学会根据业务场景选型
📚 推荐资料:
- Seata 官方文档:https://seata.io/zh-cn/docs/overview/what-is-seata/
- 《Spring Cloud Alibaba 微服务实战》书籍
- B站搜索 “Seata 事务实战”观看视频教程
🎉 恭喜你完成了你的第一个分布式事务实战项目!
如果你已经顺利跑通这个 Demo,并能理解背后的设计思想,那你就已经站在了一个很高的起点上了!
继续加油,后端开发的世界非常精彩!🚀

评论 0