分布式事务解决方案:最佳实践(适合零基础初学者)

悲观锁诗人
2025-06-27 21:59
阅读 567

开篇:什么是分布式事务?

开篇:什么是分布式事务?

在开始之前,我们先来问一个问题:

如果一个操作需要同时修改多个系统的数据,那怎么保证它们要么都成功、要么都不成功?

这就是我们要讲的“分布式事务”。

举个例子:

你在网上下单买一件商品,系统会做以下几件事:

  • 扣除库存
  • 创建订单
  • 扣减用户的账户余额

这些操作可能分别发生在不同的服务器上(即不同的服务或数据库中)。如果其中一个步骤失败了,比如库存扣除了但订单没创建成功,那整个流程就出错了。为了防止这种情况,就需要用到分布式事务

简而言之:分布式事务就是跨服务、跨数据库的事务控制机制。


环境准备:搭建开发环境(以 Spring Boot + Seata 为例)

环境准备:搭建开发环境(以 Spring Boot + Seata 为例)

为了更好地理解分布式事务,我们将使用流行的 Spring Boot 框架搭配阿里巴巴开源项目 Seata 来演示实战案例。

步骤一:安装 Java 和 Maven

  1. 下载并安装 JDK 1.8 或更高版本
  2. 下载并安装 Maven

验证是否安装成功:

java -version
mvn -v

步骤二:安装 MySQL 数据库

你可以使用 XAMPP 或直接安装 MySQL:

-- 创建两个数据库:库存和订单
CREATE DATABASE inventory;
CREATE DATABASE orders;

步骤三:下载并启动 Seata Server

  1. 前往 Seata GitHub Releases 下载 seata-server
  2. 解压后进入 bin 目录运行:
    seata-server.bat (Windows)
    sh seata-server.sh -p 8091 -m file (Linux)
    

核心概念:通俗易懂地解释关键术语

核心概念:通俗易懂地解释关键术语

我们来简单过一下几个重要概念:

概念 说明
全局事务(Global Transaction) 整个业务流程的大事务,比如一次下单
分支事务(Branch Transaction) 属于某个数据库或服务的小事务,如库存扣减、订单创建等
事务协调器(TC, Transaction Coordinator) 就是 Seata 的 server,负责协调所有小事务
事务管理器(TM, Transaction Manager) 发起事务的一方,一般是主业务服务
资源管理器(RM, Resource Manager) 各个服务里的模块,用来处理本地事务

可视化理解:

想象你在指挥一场“交响乐”:

  • TM(事务管理器)就像总指挥
  • RM(资源管理器)就像每个乐器手
  • TC(事务协调器)就像舞台上的灯光师,确保演出完美落幕

实战项目:跟着我一步步实现一个订单系统

实战项目:跟着我一步步实现一个订单系统

我们将做一个最简单的订单服务,涉及两个子系统:

  • 库存服务(Inventory Service)
  • 订单服务(Order Service)

目标:下单时同时扣库存和生成订单,如果任何一步失败,则全部回滚。


第一步:新建 Spring Boot 项目(推荐使用 Spring Initializr)

添加以下依赖:

<!-- Spring Boot -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- Seata 客户端 -->
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.6.1</version>
</dependency>

<!-- MyBatis -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>

<!-- MySQL 驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.30</version>
</dependency>

第二步:配置 Seata 客户端(application.yml)

server:
  port: 8080

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

seata:
  enabled: true
  registry:
    type: file
    nacos:
      server-addr: 127.0.0.1:8848
  tx-service-group: my_test_tx_group
  service:
    vgroup-mapping.my_test_tx_group: default
    grouplist.default: 127.0.0.1:8091

说明:Seata 默认使用 file 配置,所以不需要配置注册中心(如 Nacos),只需指定 TC 地址即可。


第三步:编写库存服务代码(InventoryService.java)

@Service
public class InventoryService {

    @Autowired
    private InventoryMapper inventoryMapper;

    @Transactional
    @GlobalLock // 锁住相关行,防止并发冲突
    public void deductStock(String productId) {
        int count = inventoryMapper.getStock(productId);
        if (count <= 0) {
            throw new RuntimeException("库存不足");
        }
        inventoryMapper.deduct(productId);
    }
}

第四步:编写订单服务代码(OrderService.java)

@Service
public class OrderService {

    @Autowired
    private InventoryService inventoryService;

    @Autowired
    private OrderMapper orderMapper;

    @GlobalTransactional  // 开启分布式事务
    public void createOrder(String productId) {
        inventoryService.deductStock(productId);  // 调用库存服务扣库存

        // 模拟异常,查看是否触发回滚
        if (productId.equals("bad")) {
            throw new RuntimeException("模拟失败");
        }

        orderMapper.createOrder(productId);  // 创建订单
    }
}

第五步:测试接口(OrderController.java)

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

    @Autowired
    private OrderService orderService;

    @PostMapping
    public String placeOrder(@RequestParam String productId) {
        try {
            orderService.createOrder(productId);
            return "订单创建成功";
        } catch (Exception e) {
            return "下单失败:" + e.getMessage();
        }
    }
}

测试结果:

访问地址:

http://localhost:8080/orders?productId=product123
  • 如果一切正常,你会看到库存减少且订单创建
  • 如果你传入 productId=bad,整个流程将回滚!

常见问题解答

问题1:Seata 启动时报错 No route to host

答:检查你的防火墙设置,确认 8091 端口开放,或者尝试关闭防火墙。


问题2:调用远程服务时报 branch register error

答:请检查配置文件中的 seata.service.grouplist.default 是否正确指向 Seata Server 的 IP 和端口。


问题3:Spring Boot 报找不到 @GlobalTransactional 注解

答:说明没有正确引入 Seata 依赖,请检查 pom.xml 中的版本号是否一致。


问题4:分布式事务为什么不能支持多语言?

答:目前 Seata 主要支持 Java,如需多语言方案,可以考虑使用其它框架如 TCC、Saga 或 Saga-based 工具如 Cadence。


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

当你掌握了本篇内容后,可以继续深入学习以下几个方向:

进阶路线图:

  1. 了解其他分布式事务方案

    • TCC(Try-Confirm-Cancel)
    • SAGA 模式
    • 最终一致性(Eventual Consistency)
    • 两阶段提交(2PC)、三阶段提交(3PC)
  2. 熟悉主流中间件与框架

    • Apache Seata(本篇已掌握 ✅)
    • Alibaba Fescar(早期 Seata 名字)
    • RocketMQ 事务消息
    • Kafka + 补偿机制
  3. 结合实际场景设计架构

    • 如何选择合适的事务方案?
    • 在什么场景下适合强一致性 vs 最终一致性?
    • 微服务之间通信如何安全可靠?
  4. 动手做更复杂项目

    • 加入支付系统、优惠券系统等
    • 接入日志追踪(SkyWalking)、限流降级(Sentinel)
    • 使用 Nacos 做配置中心和服务发现

总结回顾

在这篇教程中,我们从零开始讲解了:

  • 什么是分布式事务
  • 如何使用 Seata 实现基本的分布式事务控制
  • 通过一个订单系统示例,完成了编码与测试
  • 回顾了常见问题及其解决方法
  • 给出了清晰的学习进阶路径

希望这篇图文并茂的教程能帮助你真正理解并掌握分布式事务的核心知识。继续加油,未来的架构师之路正等着你!


🔚 如果你觉得这篇文章对你有帮助,欢迎点赞分享!

评论 0

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