分布式事务解决方案:最佳实践
开篇:什么是分布式事务?它能帮我们做什么?

在传统的单体应用中,所有的数据库操作都发生在同一个地方,比如一个银行系统的所有数据都在一台服务器上。这种结构下,如果我们需要从一个账户扣款,再给另一个账户加钱,我们可以很容易地用**本地事务(Local Transaction)**来保证这组操作要么全部成功,要么全部失败。
但随着互联网的发展,很多系统变得越来越复杂,我们把不同的功能拆分成了多个微服务,每个微服务都有自己的数据库。这样做的好处是更灵活、更易扩展,但也带来了一个新问题:
不同数据库之间的事务如何协调,才能保证数据一致性?
这就是我们要讲的“分布式事务(Distributed Transaction)”。
举个例子:假设你在一个电商平台下单买了一本书,这个请求可能会触发下面几个操作:
- 订单服务:创建订单
- 库存服务:减少库存数量
- 支付服务:扣除用户账户的钱
这三个操作分别由三个独立的服务完成,它们可能访问的是不同的数据库。如果其中有一个步骤失败了,我们必须确保其他两个也不生效,否则就会出现“钱收了但是不发货”的情况。
所以,分布式事务就是要解决跨服务、跨数据库之间的一致性问题。它就像是一场多人参与的合作任务,所有人都要统一行动,只要一人出错,就全部回滚。
环境准备:开发环境搭建指南
本教程使用的技术栈包括:
- Java 17(或以上)
- Spring Boot + Spring Cloud
- Maven(项目构建)
- Redis 和 MySQL(作为数据库演示)
- Nacos(作为注册中心和配置中心)
- Seata(开源分布式事务框架)
第一步:安装Java开发工具包(JDK)
请前往 https://www.oracle.com/java/technologies/javase-downloads.html 下载并安装 JDK 17 或以上版本。
第二步:安装IDE(推荐IntelliJ IDEA)
下载地址:https://www.jetbrains.com/idea/
第三步:安装Maven
可以从官网下载:https://maven.apache.org/download.cgi 安装完成后,在终端执行以下命令确认是否安装成功:
mvn -v
第四步:安装MySQL和Redis
安装MySQL
推荐使用Docker快速部署:
docker run -p 3306:3306 --name mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-d mysql:8.0
安装Redis
同样使用Docker:
docker run -p 6379:6379 --name redis \
-d redis:latest
第五步:安装Nacos Server
GitHub地址:https://github.com/alibaba/nacos/releases
下载后解压,启动方式如下(Windows):
startup.cmd -m standalone
访问 http://localhost:8848/nacos 进入控制台,默认账号密码都是 nacos/nacos。
第六步:安装Seata Server
下载地址:https://seata.io/en-us/blog/download.html
配置文件修改要点:
- 修改
registry.conf中的注册中心为 Nacos - 启动 Seata Server:
sh seata-server.sh -p 8091 -h 127.0.0.1 -m db
核心概念:轻松理解分布式事务的关键术语

为了让大家更好地理解分布式事务,我们先来看一些关键术语,并用生活中的类比来帮助理解:
| 术语 | 生活比喻 | 简单解释 |
|---|---|---|
| 分布式事务 | 小组合作完成一个大任务 | 多个系统一起完成一项业务,必须同时成功或回滚 |
| 全局事务 ID(XID) | 团队的任务编号 | 每次分布式事务有一个唯一ID,所有参与的服务都知道它是哪一个任务的一部分 |
| TC(Transaction Coordinator) | 队长、协调员 | 负责协调各个服务,决定事务是提交还是回滚 |
| RM(Resource Manager) | 组员 | 各个服务,负责本地事务操作 |
| TM(Transaction Manager) | 总负责人 | 发起事务,并决定最终是否提交 |
分布式事务的工作流程(以 Seata 为例)
- 用户发起下单请求(TM开始事务)
- 订单服务生成订单(RM1记录日志)
- 库存服务减少库存(RM2记录日志)
- 支付服务扣款(RM3记录日志)
- 所有服务报告状态给TC
- 如果都成功 → 提交事务
- 如果任一失败 → 所有服务回滚
实战项目:手把手做一个简单的分布式事务项目
我们将模拟一个电商系统的下单流程,包含三个服务:
- 订单服务
- 库存服务
- 支付服务
所有服务使用 Seata 实现分布式事务控制。
第一步:新建Spring Boot工程(使用Maven)
创建一个父工程 distributed-transaction-demo,然后分别创建三个子模块:
- order-service
- inventory-service
- payment-service
第二步:添加依赖(以订单服务为例)
在 order-service/pom.xml 添加:
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2022.0.0.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
</dependencies>
其他服务类似,略去。
第三步:配置Nacos和服务注册
在 application.yml 中配置注册信息(以订单服务为例):
server:
port: 8081
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
记得在主程序加上注解:
@EnableDiscoveryClient
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
第四步:配置Seata
在 resources 下新建 file.conf 和 registry.conf 文件,内容参考 Seata 官方模板。
第五步:写代码实现下单功能
我们以订单服务为主服务,调用库存和支付服务。
订单服务接口:
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping("/create")
public String createOrder() {
try {
orderService.createOrder();
return "Order created successfully.";
} catch (Exception e) {
return "Failed to create order: " + e.getMessage();
}
}
}
订单服务业务逻辑(使用@GlobalTransactional 开启全局事务):
@Service
public class OrderService {
@Autowired
private InventoryService inventoryService;
@Autowired
private PaymentService paymentService;
@Autowired
private OrderRepository orderRepository;
@GlobalTransactional // 开启分布式事务
public void createOrder() {
// 1. 创建订单
Order order = new Order("1", "book", "user1");
orderRepository.save(order);
// 2. 减少库存
inventoryService.decreaseStock("book");
// 3. 扣款
paymentService.deductMoney("user1", 39.9);
}
}
库存服务接口:
@RestController
@RequestMapping("/inventory")
public class InventoryController {
@Autowired
private InventoryService inventoryService;
@PostMapping("/decrease")
public String decreaseStock(@RequestParam String productId) {
inventoryService.decreaseStock(productId);
return "Stock decreased for product: " + productId;
}
}
支付服务接口:
@RestController
@RequestMapping("/payment")
public class PaymentController {
@Autowired
private PaymentService paymentService;
@PostMapping("/deduct")
public String deductMoney(@RequestParam String userId, @RequestParam double amount) {
paymentService.deductMoney(userId, amount);
return "Deducted " + amount + " from user: " + userId;
}
}
启动测试
启动所有服务后,访问:
POST http://localhost:8081/order/create
如果一切顺利,你会看到订单、库存和支付三个服务都完成了操作。
如果你故意让某一个服务抛出异常,整个事务会回滚,确保数据一致性。
常见问题解答:初学者常问的问题
Q1:为什么不能直接使用本地事务?
因为本地事务只能管理一个数据库连接,而分布式事务涉及多个服务、多个数据库,无法通过传统的本地事务机制来协调。
Q2:Seata 是不是必须的?有没有替代方案?
Seata 是目前最流行的开源方案之一,但它不是唯一的。常见的还有 Atomikos、TCC、Saga等。选择哪一种取决于你的业务需求和技术栈。
Q3:如果其中一个服务宕机怎么办?
这是个好问题!在真实环境中,服务可能不可用。Seata 内部有重试机制和异步补偿机制,能在一定程度上自动处理这种情况。
Q4:Seata 的性能怎么样?
引入分布式事务确实会增加一定的网络开销,但实际生产中通过优化可以接受。建议在必要时才使用,避免滥用。
Q5:学习分布式事务需要先掌握什么基础知识?
建议先了解:
- Spring Boot 基础
- Spring Cloud 微服务
- REST API 和远程调用
- 数据库事务(ACID 特性)
- CAP 定理基础
学习建议:下一步怎么深入学习?
恭喜你已经完成了第一个分布式事务项目的实战!
接下来你可以沿着以下几个方向继续深入:
方向一:掌握其他主流分布式事务方案
除了 Seata,你还应该了解:
- TCC(Try-Confirm-Cancel)模式
- 更灵活,适用于高并发场景
- SAGA 模式
- 适用于长时间运行的业务流程
- 消息驱动事务(如 RocketMQ 事务消息)
- 利用消息队列实现最终一致性
方向二:研究Seata底层原理
深入了解 Seata 的 AT 模式是如何工作的:
- 如何自动生成 undo_log 表?
- 如何解析 SQL 并进行反向补偿?
- 如何与 Nacos 配合做注册发现?
方向三:结合实际业务场景优化
比如:
- 如何做幂等设计?
- 如何设置事务超时时间?
- 如何做异步补偿机制?
方向四:阅读源码和文档
官方文档是最好的参考资料:
- Seata 官网:https://seata.io
- Spring Cloud Alibaba 官方文档:https://github.com/alibaba/spring-cloud-alibaba
结语:坚持就是进步的动力
分布式事务是微服务架构中非常重要的一环。虽然刚开始看起来有点复杂,但只要你肯动手实践,逐步理解每一个环节,就能掌握这项核心技能。
记住一句话:
“编程没有捷径,只有不断练习和思考。”
希望这篇教程能成为你学习路上的一个坚实台阶。加油,未来的架构师!

评论 0