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

王者.梁丽.先锋
2025-06-23 14:20
阅读 223

开篇:什么是分布式事务?为什么要学它?

开篇:什么是分布式事务?为什么要学它?

我们先来想象这样一个场景:

你用手机在某宝上买了一件衣服,付款后商家就安排发货。这个时候,系统内部会发生几件事:

  1. 钱从你的账户扣掉;
  2. 商家库存减少一件;
  3. 物流系统记录快递信息。

如果这些操作不是在同一个数据库里完成,而是分布在不同的服务中(例如支付服务、库存服务、物流服务),那么就需要一种机制,确保这三个操作要么全部成功,要么都不做。否则就会出现“钱被扣了但衣服没发”或者“衣服发了但不收钱”的尴尬情况。

这种跨多个服务/数据库的一系列操作要一起成功或一起失败的需求,就是 分布式事务 要解决的问题。

为什么你要学习它?

  • 如今很多公司都在使用微服务架构,数据分散在不同服务中。
  • 如果不懂分布式事务,系统容易出现数据不一致的问题。
  • 这是中高级后端工程师必须掌握的核心技能之一。

环境准备:搭建开发环境

环境准备:搭建开发环境

本教程将使用 Java 技术栈 + Spring Boot 框架 + Seata(一个开源分布式事务框架)来进行讲解。

所需软件列表

名称 用途 安装要求
JDK 8 或以上 编译运行Java程序 必须安装
IntelliJ IDEA 编写和调试代码 推荐
MySQL 5.7+ 存储模拟数据 必须安装
Maven 项目依赖管理 必须安装
Seata Server 实现分布式事务控制 必须安装

步骤一:安装并配置Seata Server

  1. 前往 Seata官网 下载 seata-server
  2. 解压到本地目录,进入 conf/start.sh(Linux/Mac)或 start.bat(Windows)启动Seata服务。
  3. 默认情况下,Seata监听的是 8091端口(TC)8099端口(REST)

提示:如果你希望看到日志输出更清晰,可以在启动脚本中加入 -d 参数(debug模式)。


步骤二:配置MySQL数据库

  1. 创建两个库:order_dbstock_db

    CREATE DATABASE order_db;
    CREATE DATABASE stock_db;
    
  2. 在这两个库中分别创建表:

order_db: orders 表:

CREATE TABLE orders (
  id INT AUTO_INCREMENT PRIMARY KEY,
  user_id VARCHAR(255),
  product_id VARCHAR(255),
  status VARCHAR(255)
);

stock_db: products 表:

CREATE TABLE products (
  id VARCHAR(255) PRIMARY KEY,
  name VARCHAR(255),
  stock INT
);

步骤三:初始化Spring Boot项目

使用 Spring Initializr 创建一个新的Spring Boot项目:

  • Group: com.example
  • Artifact: distributed-demo
  • Dependencies:
    • Spring Web
    • MyBatis Framework
    • MySQL Driver

然后导入IDEA,并添加 Seata Starter 依赖:

pom.xml 中添加:

<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.6.1</version>
</dependency>

核心概念:通俗易懂地讲明白关键术语

核心概念:通俗易懂地讲明白关键术语

什么是分布式事务?

  • 就是“一次操作涉及多个服务”,而这些服务各自都有自己的数据库。
  • 要保证这些服务要么都做,要么都不做。

举个简单的例子:

小明下单买书,系统要做的几个动作:

  1. 减用户积分 ✅
  2. 扣书籍库存 ✅
  3. 添加订单记录 ✅

如果中间任何一步出错,都应该回滚所有已经完成的操作,让一切回到原始状态。


分布式事务常用解决方案介绍(按难度递增)

方案名称 是否推荐 适用场景 说明
两阶段提交 (2PC) ❌ 不推荐 简单场景 效率低,性能差
TCC(Try-Confirm-Cancel) ✅ 强烈推荐 中高并发 控制粒度细,适合业务复杂系统
Saga 模式 ✅ 推荐 长时间流程 支持异步任务,如审批流程
最终一致性(通过消息队列补偿) ✅ 推荐 非强一致性需求 数据最终对得上就行
Seata AT 模式 ✅ 极力推荐 新项目首选 自动处理事务日志,对代码侵入少

Seata 是什么?

Seata 是阿里巴巴开源的一个分布式事务解决方案。

它支持多种模式,我们重点介绍最常用的 AT模式(Auto Transaction Mode)

AT模式的工作原理(简单理解):

  1. 在每个数据库操作前加锁(预处理)
  2. 修改完数据之后,把变更记录写进 undo_log 表
  3. 如果其中一个服务失败,则通过 undo_log 回滚之前的所有改动
  4. 成功则清理 undo_log 日志

优点:开发者几乎不需要修改业务逻辑,Seata自动帮你处理!


实战项目:编写一个分布式事务案例

我们来做一个最基础的例子:用户下单时,同时修改订单表和库存表,用 Seata 管理事务。

第一步:创建微服务模块结构

我们将构建两个微服务:

  • order-service:负责订单相关逻辑
  • stock-service:负责库存相关逻辑

两个服务之间通过 Feign 调用进行通信。


第二步:添加Seata客户端配置

在两个服务的 application.yml 文件中,添加如下配置:

seata:
  enabled: true
  application-id: ${spring.application.name}
  tx-service-group: default_tx_group
  service:
    vgroup-mapping:
      default_tx_group: default
    grouplist:
      default: 127.0.0.1:8091
  config:
    type: file

注意:确保你本地已启动 Seata Server,默认地址为 127.0.0.1:8091


第三步:创建两个服务接口

1. stock-service 的控制器

@RestController
@RequestMapping("/stock")
public class StockController {

    @PostMapping("/reduce")
    public String reduceStock(@RequestParam("productId") String productId) {
        // 这里实际操作数据库,减库存
        System.out.println("库存扣减完成:" + productId);
        return "success";
    }
}

2. order-service 的控制器

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

    @Autowired
    private OrderService orderService;

    @PostMapping("/create")
    @GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
    public String createOrder() throws Exception {
        try {
            orderService.createOrder();
            return "订单创建成功";
        } catch (Exception e) {
            throw new RuntimeException("创建订单失败");
        }
    }
}

注意:@GlobalTransactional 是 Seata 提供的注解,表示这个方法是一个全局事务入口。


第四步:调用库存服务(Feign Client)

@FeignClient(name = "stock-service")
public interface StockClient {
    @PostMapping("/stock/reduce")
    String reduceStock(@RequestParam("productId") String productId);
}

确保你的主类开启了 FeignClient 功能。


第五步:业务层实现订单创建逻辑

@Service
public class OrderService {

    @Autowired
    private StockClient stockClient;

    @Autowired
    private OrderMapper orderMapper;

    public void createOrder() {
        String productId = "123456";

        // 1. 调用库存服务减库存
        String result = stockClient.reduceStock(productId);

        if (!"success".equals(result)) {
            throw new RuntimeException("库存不足");
        }

        // 2. 插入订单记录
        Orders order = new Orders();
        order.setUserId("user_001");
        order.setProductId(productId);
        order.setStatus("paid");
        orderMapper.insert(order);
    }
}

第六步:测试分布式事务是否生效

你可以故意让 stockClient.reduceStock() 方法抛出异常,查看数据库中是否有插入数据。如果没有插入,说明 Seata 正确实现了回滚。


常见问题解答(FAQ)

数据流转过程-1

问题 1:Seata 启动失败怎么办?

可能原因:

  • 端口冲突(查看8091是否已被占用)
  • 系统资源不足(内存或CPU)

解决办法:

  • 更换端口号(编辑 file.conf
  • 提升硬件配置或关闭其他占用资源的服务

问题 2:事务没有回滚怎么办?

检查以下几点:

  • 方法是否有 @GlobalTransactional 注解?
  • 是否在 Controller 层调用事务方法?应放在 Service 层!
  • 抛出的异常是否属于 rollbackFor 允许的范围?

问题 3:undo_log 表作用是什么?

这是 Seata 记录事务前后数据快照的地方。用于事务回滚时还原数据。

你无需手动维护此表,Seata 会自动处理。


问题 4:我能不能不引入第三方框架自己实现分布式事务?

理论上可以,但代价很高。

  • 需要你自己实现事务协调器
  • 错误处理、网络中断、重试机制都需要考虑
  • 性能优化也非常复杂

建议初学者直接使用成熟的方案(如 Seata)入门。


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

恭喜你完成了第一个分布式事务实战项目!但这只是旅程的开始。

接下来你可以按照这条路径继续深入学习:

第一阶段:夯实基础

✅ 掌握 Spring Cloud Alibaba + Nacos(服务注册发现)
✅ 学习 RocketMQ(消息队列)实现最终一致性
✅ 学会使用 Redis 作为临时状态存储

第二阶段:掌握主流方案

✅ 掌握 TCC 模式的使用方式(适用于金融交易系统)
✅ 实践 Saga 模式(适用于长时间流程业务)
✅ 使用 XA 模式了解底层数据库交互方式

第三阶段:进阶与性能优化

✅ 深入源码解读 Seata 内部原理(适合面试加分)
✅ 学习如何监控和追踪事务链路(SkyWalking / Zipkin)
✅ 结合大数据场景处理海量事务数据(如电商业务秒杀)


结语:分布式事务并不难,关键是动手实践

分布式事务虽然听起来“高端大气”,但只要你动手尝试几次,结合 Seata 等成熟工具,就能轻松掌握这项关键技术。

记住一句话:最好的学习方式,就是边看文档边敲代码。

现在你已经掌握了环境搭建、基本概念、实战开发以及常见问题的处理方法。别停在这里,继续探索吧!


📚 文章总字数约:3601 字
💡 预计阅读时间:20~30分钟
🎯 学习建议:跟着步骤一步步搭建项目,不要只看不动手!

如需配套源码项目,欢迎留言评论获取 GitHub 仓库地址 👇

评论 0

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