分布式事务解决方案:最佳实践(适合零基础新手的教程)

创新App
2025-06-19 22:03
阅读 644

开篇:什么是分布式事务?它用来做什么?

开篇:什么是分布式事务?它用来做什么?

在我们开发一个软件系统时,有时候我们需要同时操作多个数据库或服务。比如你在网上下单买了一件商品,系统需要做几件事情:

  1. 扣除你的余额
  2. 减少库存数量
  3. 记录订单信息

这些操作通常分布在不同的服务中,比如用户服务、库存服务、订单服务。它们可能有自己的数据库。

这就带来了一个问题:如果其中某个步骤出错了,其他操作也得回退,否则数据就会不一致了。就像你在ATM取钱失败,账户不该被扣钱一样。

而解决这个问题的技术手段,就叫做——分布式事务

一句话总结
分布式事务就是让我们在多个服务/数据库之间进行“要么一起成功,要么一起失败”的操作控制机制。


环境准备:搭建开发环境

环境准备:搭建开发环境

要学习和练习分布式事务的实现方式,我们需要准备好以下工具和环境:

✅ 1. 安装 JDK 和 Maven(Java语言为例)

新手提醒:建议安装 JDK 8 或 11,版本稳定,兼容性好。

设置环境变量后,在命令行执行下面两个命令验证是否安装成功:

java -version
mvn -v

✅ 2. 安装 Spring Boot(用于搭建微服务)

Spring Boot 是当前最流行的 Java Web 框架,特别适合用来构建微服务项目。

你可以去 Spring Initializr 生成一个空的项目脚手架。

选择如下依赖项:

  • Spring Web
  • Spring Data JPA
  • MySQL Driver
  • Spring Cloud Feign(用于服务间通信)
  • Lombok(简化代码)

不会用?没关系,后面实战项目我们会一步步写出来!

✅ 3. 安装 MySQL 数据库

下载地址:MySQL官网

安装完成后,创建两个数据库:

  • user_db(用户数据库)
  • product_db(商品数据库)

这样我们可以模拟两个不同的服务使用不同的数据库。

✅ 4. 使用 Postman 调试接口(可选)

Postman 是一个测试 API 接口的神器,可以用来测试我们的 RESTful 接口请求是否正常。


核心概念:通俗讲解分布式事务关键概念

现在我们来理解几个核心名词,尽量用白话解释:

🔹 1. 本地事务(Local Transaction)

就是我们在单一数据库中常用的操作,比如一个 service 方法里,我们对数据库做了插入和更新操作,并且通过事务保证这两个操作同时成功或失败。

例子(伪代码):

@Transactional
public void buyProduct() {
    deductBalance();  // 扣款
    decreaseStock();  // 减库存
}

但如果这两个方法分别调用了两个数据库(即分布在不同服务中),就不适用了,这时候就需要分布式事务。


🔹 2. 全局事务(Global Transaction)

这是分布式事务的核心概念,指的是:跨多个服务或数据库的事务协调

举个例子:

  • 用户服务 -> 用户数据库
  • 库存服务 -> 商品数据库

我们希望这两个服务都参与一个全局事务,要么都成功,要么都失败。


🔹 3. CAP定理与BASE理论

这两个是分布式系统的理论支撑,了解即可:

➤ CAP定理(一致性 Consistency、可用性 Availability、分区容忍 Partition tolerance)

  • 三者只能满足其二
  • 我们的系统不能同时做到强一致性和高可用,还要能忍受网络故障

➤ BASE理论(基本可用 Basically Available,柔性状态 Soft-state,最终一致 Eventually consistent)

  • 强调系统的最终一致性而非实时一致性,更适合大规模分布式的场景

🔹 4. 常见的分布式事务解决方案

解决方案 是否支持跨服务 是否复杂 适用场景
两阶段提交(2PC) ⚠️复杂 对数据一致性要求极高,但性能差
TCC(Try-Confirm-Cancel) ⚠️较复杂 高并发业务场景
Seata ⚠️适中 微服务架构下推荐
RocketMQ / Kafka 事件驱动 ⚠️中等 最终一致性为主

🚨 初学者建议先掌握 TCC 和 Seata,这两个是最实用、最流行的方案。


实战项目:一步一步实现一个分布式事务案例

我们将用 Spring Boot + Seata 来完成一个简单的案例:用户购买商品功能。

整个过程分为以下几个服务:

  • 用户服务(User Service):管理用户余额
  • 库存服务(Product Service):管理商品库存
  • 订单服务(Order Service):记录订单并发起交易请求
  • Seata Server:负责协调分布式事务

第一步:创建三个 Spring Boot 项目

✅ 创建 User Service

创建一个 Spring Boot 项目,加入如下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

配置文件 application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/user_db?useSSL=false&serverTimezone=UTC
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

编写业务逻辑类 UserService.java

@Service
public class UserService {

    @Autowired
    UserRepository userRepository;

    @GlobalTransactional  // 分布式事务注解
    public void deductBalance(Long userId, BigDecimal amount) {
        // 扣减余额
        User user = userRepository.findById(userId).get();
        user.setBalance(user.getBalance().subtract(amount));
        userRepository.save(user);
    }
}

类似地,我们也为 Product Service 编写一个减少库存的方法。


第二步:启动 Seata Server(TC组件)

Seata 是阿里巴巴开源的分布式事务框架,它有三个核心角色:

  • TC(Transaction Coordinator):事务协调器,负责全局事务注册和协调
  • TM(Transaction Manager):事务管理者,决定是否提交事务
  • RM(Resource Manager):资源管理者,管理各个服务的数据源

👉 下载地址:Seata GitHub Release

按照文档启动 Seata Server,默认端口:8091


第三步:集成 Seata Client 到各个服务

每个 Spring Boot 项目都需要引入 Seata Client 并连接上 Seata Server。

添加 Seata 相关配置到 application.yml

seata:
  enabled: true
  application-id: ${spring.application.name}  # 每个服务名字唯一
  tx-service-group: my_test_tx_group

还需要将数据库代理配置修改为 Seata 的:

确保使用 druid 数据源并加入如下配置:

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    seata: true

第四步:编写 Order Service 发起交易流程

Order Service 是调用方,它会调用其他两个服务。

@RestController
@RequestMapping("/orders")
public class OrderController {

    @Autowired
    UserService userService;

    @Autowired
    ProductService productService;

    @PostMapping
    @GlobalTransactional
    public String placeOrder(@RequestBody OrderDTO dto) {
        try {
            userService.deductBalance(dto.getUserId(), dto.getAmount());
            productService.decreaseStock(dto.getProductId(), dto.getCount());
            return "订单创建成功";
        } catch (Exception e) {
            throw new RuntimeException("事务回滚");
        }
    }
}

缓存策略对比-2

第五步:运行整个项目并测试

依次启动:

  • Nacos(作为服务发现,如使用 Spring Cloud Alibaba)
  • Seata Server
  • User Service
  • Product Service
  • Order Service

用 Postman 发送 POST 请求:

{
  "userId": 1,
  "productId": 1,
  "amount": 100.00,
  "count": 1
}

✅ 如果成功,余额和库存都会减少;
❌ 如果抛异常,两个数据库都不会变化(自动回滚)。


常见问题解答(FAQ)

Q1: 为什么我启动 Seata 报错说 connect refused?

A: 可能是 Seata 服务未启动,或者配置的 IP 地址不对,请确认是否开启服务,并查看日志是否有报错。

Q2: 用不了 Seata 怎么办?

A: 你可以尝试使用 TCC 模式(手动实现 Try/Confirm/Cancel)或使用 消息队列实现最终一致性

Q3: 为什么用分布式事务会影响性能?

A: 分布式事务会增加额外的通信开销,比如需要 TC 协调,所以它比本地事务慢一些。一般用于关键业务环节,如支付、下单、转账等。

Q4: 我不想用 Java,可以用其他语言吗?

A: 当然可以!比如 Go 有 DTM、Python 也有类似框架。但 Spring Cloud + Seata 是目前最成熟的组合,尤其适合企业级应用。


学习建议:下一步怎么学更好?

恭喜你完成了本课程的第一步!接下来推荐的学习路径如下:

📘 第一阶段:巩固基础

📗 第二阶段:拓展方案

  • 学习 TCC 模式,了解其补偿机制
  • 尝试基于 RocketMQ 实现异步最终一致性

📙 第三阶段:实战进阶

  • 在真实项目中集成分布式事务
  • 学习服务链路追踪(如SkyWalking)、监控日志系统

📒 第四阶段:深入底层原理

  • 学习 Seata 的 AT 模式原理
  • 掌握 XA、Saga 模式的工作机制
  • 阅读源码,看看它是如何做锁资源、回滚日志、事务分组等工作的

结语

API接口文档-1

学习分布式事务可能会让你一开始觉得有点难,尤其是那些专业术语和复杂的结构图。但只要你动手写了第一个完整的案例,你会发现它其实并不神秘

就像你第一次学写 Hello World 一样,从今天这篇教程开始,你就已经踏上成为高级后端工程师的路了。

如果你喜欢这样的教学风格,欢迎持续关注,我会继续为你输出更多实战型技术文章!

🎯 保持学习的热情,未来可期!

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝