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

梁红
2025-06-28 18:56
阅读 598

一、开篇:分布式事务是做什么的?

一、开篇:分布式事务是做什么的?

你有没有遇到过这样的问题:比如你在购物网站下单,扣款成功了,但订单却没有生成?或者在银行转账时,钱被转出但没有到账?

这些问题都和“事务”有关。事务就是一系列操作要一起成功,要么一起失败。

但在现代系统中,往往数据分布在不同的服务或数据库中。例如:

  • 用户服务有自己的用户表
  • 订单服务有自己的订单表
  • 库存服务有自己的库存记录

这个时候,如果我们要做一次“下单扣库存”的操作,就需要这三个服务之间的数据保持一致。

这就引出了一个关键的技术点:分布式事务 —— 它是用来保证跨多个服务的数据一致性的一种机制。

场景举例:

比如你要买一件衣服:

  1. 用户下单 → 订单服务创建订单
  2. 扣除库存 → 库存服务减去1件商品
  3. 扣除余额 → 用户账户服务扣除金额

这三项操作必须全部成功或全部失败,不能只完成其中两个。


二、环境准备:搭建开发环境

二、环境准备:搭建开发环境

为了更好地理解分布式事务,我们使用以下技术栈进行实操:

  • Java(推荐JDK 8或以上)
  • Spring Boot(框架)
  • MySQL(作为数据库)
  • Seata(阿里开源的分布式事务中间件)
  • Maven(项目依赖管理工具)

步骤1:安装JDK和IDE

你可以选择以下任意一个开发环境:

  • IntelliJ IDEA(推荐新手用Ultimate版)
  • Eclipse + JDK

安装步骤略过,因为不是本教程重点。

步骤2:安装MySQL

  1. 下载并安装 MySQL
  2. 创建两个测试数据库:
    CREATE DATABASE order_service;
    CREATE DATABASE inventory_service;
    

步骤3:安装Seata Server

  1. Seata官网 下载 seata-server
  2. 解压后进入 bin 目录,运行启动脚本:
    seata-server.sh -p 8091 -m file
    
    (Windows用对应的 .bat 文件)

这样你就准备好了一个可以处理分布式事务的中间件!


三、核心概念:通俗解释关键技术

1. 什么是本地事务?

本地事务指的是在同一台服务器上的数据库事务,例如在一个数据库中对订单进行增删改查,这类事务天然支持 ACID 特性(原子性、一致性、隔离性、持久性)。

2. 分布式事务中的三大角色

角色 作用
TC(Transaction Coordinator) 协调者,即Seata Server,负责协调各个事务分支
TM(Transaction Manager) 事务发起方,决定全局事务的提交或回滚
RM(Resource Manager) 资源管理者,通常是各个数据库,执行本地事务

3. 分布式事务常用方案介绍(适合初学者)

方案名 简介 优点 缺点
2PC(两阶段提交) 典型的同步阻塞型协议 数据强一致性 可靠性低、性能差
TCC(Try-Confirm-Cancel) 通过业务逻辑控制 性能高、灵活 实现复杂、需人工编写补偿逻辑
Saga 模式 每个操作都有补偿动作 高性能、适用于长周期任务 补偿逻辑复杂,容易出错
消息队列+本地事务表 异步解耦方式 高并发 实现较复杂,需维护事务状态
Seata(AT模式) 自动代理数据库事务 对代码侵入少、易集成 需引入中间件

✅ 推荐入门学习顺序:Seata AT 模式 → TCC → Saga → 2PC


四、实战项目:用 Seata 实现一个简单订单+库存扣减场景

数据库设计模型-1

项目目标

实现一个“下单时扣库存”的功能,并确保这两个操作要么同时成功,要么同时失败。

1. 创建两个Spring Boot模块

我们分别创建两个Spring Boot项目:

  • order-service(订单服务)
  • inventory-service(库存服务)

两个服务都会连接自己的数据库,并接入Seata。

2. 引入Seata依赖(以order-service为例)

pom.xml 中添加:

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

同时,在配置文件 application.yml 中加入:

seata:
  enabled: true
  application-id: order-service
  tx-service-group: my_tx_group
  service:
    vgroup-mapping:
      my_tx_group: default
    grouplist:
      default: 127.0.0.1:8091

这个配置告诉Spring Boot,我们启用了Seata,并连接到本地运行的Seata Server。

3. 编写订单服务接口(order-service)

@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private RestTemplate restTemplate;

    // 开启分布式事务
    @GlobalTransactional
    public void placeOrder(String productId, int quantity) {
        // 1. 插入订单
        Order order = new Order(productId, quantity);
        orderRepository.save(order);

        // 2. 调用库存服务,减少库存
        String url = "http://localhost:8081/inventory/deduct?productId=" + productId + "&quantity=" + quantity;
        ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);

        if (!response.getStatusCode().is2xxSuccessful()) {
            throw new RuntimeException("库存扣减失败");
        }
    }
}

4. 编写库存服务接口(inventory-service)

@RestController
@RequestMapping("/inventory")
public class InventoryController {

    @PostMapping("/deduct")
    public String deductInventory(@RequestParam String productId, @RequestParam int quantity) {
        // 假设这里从数据库扣除库存
        boolean success = InventoryDB.deduct(productId, quantity);
        if (success) {
            return "OK";
        } else {
            return "Fail";
        }
    }
}

微服务架构示意图-2

5. 测试流程

  1. 启动 Seata Server
  2. 启动 inventory-service
  3. 启动 order-service
  4. 调用 order-service/placeOrder 接口:
    curl http://localhost:8080/order/place?productId=1001&quantity=1
    

如果你模拟一个错误(比如库存不足),抛出异常后,你会看到订单不会插入,也不会减少库存 —— 这就是Seata的作用!


五、常见问题与解答

Q1:我启动了Seata,但是提示连接不上TC怎么办?

A:请检查Seata Server是否已启动,端口是否是 8091。查看日志是否有报错信息。


Q2:使用@GlobalTransactional注解的方法需要满足什么条件?

A:

  • 必须标注在服务层方法上
  • 方法必须为public
  • 类必须被Spring管理(加@Component或@Service)

Q3:为什么我测试的时候事务没回滚?

A:

  • 确保所有服务都正确接入Seata
  • 确保抛出的是RuntimeException
  • 不要在 try-catch 中吃掉异常

Q4:Seata支持哪些数据库?

A:目前支持常见的主流数据库,包括 MySQL、Oracle、PostgreSQL 等。


六、下一步学习建议

恭喜你完成了第一课!现在你已经具备了分布式事务的基础知识和初步实战能力。

下一步你可以学习的方向包括:

1. 学习其他分布式事务方案

  • 理解 TCC 设计模式(手动补偿机制)
  • 学习 Saga 模式的业务适用场景
  • 尝试用 RabbitMQ 实现异步事务补偿

2. 深入理解 Seata 工作原理

  • 查看 GlobalSession 是如何工作的
  • 了解 AT 模式是如何拦截 SQL 并生成 Undo Log 的
  • 学习 Seata 配置中心(如Nacos)的使用

3. 结合微服务架构深入实践

  • 使用 Nacos 或 Eureka 做服务注册发现
  • 使用 Feign 或 Dubbo 进行服务通信
  • 整合 Redis 缓存优化查询性能

结语:分布式事务并不神秘!

很多同学一开始觉得分布式事务很高级很难,其实只要你掌握了基本的概念和常用的实践方案,它就是一个“高级一点的一致性保障手段”。

希望这篇教程帮你打开了通往分布式系统的又一扇门。继续加油,未来可期!


📌 资源链接推荐:

评论 0

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