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

限流小保安
2025-06-24 14:43
阅读 399

一、开篇:什么是分布式事务?我们为什么需要它?

一、开篇:什么是分布式事务?我们为什么需要它?

在开发大型系统时,比如电商平台、银行转账系统等,经常会遇到这样的问题:

用户下单购买商品的同时,还要扣减库存和账户余额。如果其中一个操作失败了该怎么办?

这时候,我们就会用到“分布式事务”来确保整个流程要么全部成功,要么全部失败,不会出现中间状态。

简单来说,分布式事务就是:在多个服务或数据库中执行一组操作,并保证这些操作的“原子性”,也就是要不全做,要不全不做。


二、环境准备:搭建我们的开发环境

二、环境准备:搭建我们的开发环境

本教程使用 Java + Spring Boot + Seata 实现一个简单的分布式事务示例。以下是必要的准备工作:

安装工具清单:

  1. JDK 1.8+
  2. Maven 3.6+
  3. IntelliJ IDEA(或其他IDE)
  4. MySQL 5.7+
  5. Seata 1.6+

步骤1:安装 MySQL 并创建数据库和表

-- 创建两个库:订单库、库存库
CREATE DATABASE order_db;
CREATE DATABASE inventory_db;

-- 使用 order_db
USE order_db;
CREATE TABLE orders (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT,
    product_id BIGINT,
    count INT,
    status VARCHAR(20)
);

-- 使用 inventory_db
USE inventory_db;
CREATE TABLE inventory (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    product_id BIGINT,
    stock INT
);

步骤2:启动 Seata Server(简化版)

  1. 到官网下载 Seata
  2. 解压后进入 conf 目录,修改配置文件为支持你本地的数据库
  3. 启动 Seata:
    cd seata-server
    sh startup.sh -p 8091 -m file
    

三、核心概念:用大白话讲清楚关键技术点

1. 分布式事务 vs 单体事务

  • 单体事务:一个数据库里完成所有操作(简单好控制)
  • 分布式事务:多个服务、数据库之间协调完成事务(复杂但更真实)

2. XA、TCC、SAGA、MQ 模型对比

模型 描述 优点 缺点
XA 强一致性方案,基于两阶段提交 稳定、数据准确 性能低,资源锁定时间长
TCC Try-Confirm-Cancel 三步机制 高性能 开发难度大,需人工补偿
SAGA 将事务拆成小步骤,失败就逆向回滚 可扩展性强 错误处理逻辑复杂
MQ 基于消息队列实现最终一致 异步处理、吞吐高 数据延迟,可能不一致

我们以 Seata 中的 AT 模式为例,演示最常用的一种方式。


四、实战项目:跟着我一起写一个简单的分布式事务案例

场景说明:

我们需要完成如下业务:

  • 用户下订单
  • 库存系统减少对应库存数量
  • 如果其中一步失败,整个操作回滚(不能只下单没减库存,也不能减了库存却没下单)

技术架构图简述:

用户 -> 下单服务(order-service) 
        ↓ 调用 ↓
      库存服务(inventory-service)

我们先创建两个 Spring Boot 项目:

  1. order-service(订单服务)
  2. inventory-service(库存服务)

我们使用 Feign 进行服务调用,Seata 实现事务管理。


第1步:添加 Maven 依赖(以 order-service 为例)

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

其他依赖略(MySQL驱动、Spring Web、MyBatis、Feign)


第2步:配置 Seata 在 application.yml 文件中

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

inventory-service 同理,只是应用ID不同。


第3步:编写 OrderController.java(订单接口)

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

    @Autowired
    private OrderService orderService;

    @GetMapping("/create")
    public String createOrder() {
        try {
            orderService.createOrder();
            return "订单创建成功";
        } catch (Exception e) {
            return "订单创建失败:" + e.getMessage();
        }
    }
}

第4步:编写 OrderService.java(包含远程调用库存服务)

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private InventoryServiceFeignClient inventoryClient;

    @GlobalTransactional // Seata 的全局事务注解
    public void createOrder() {
        // 1. 创建订单
        orderMapper.insertOrder(1L, 1001L, 2); // 用户ID=1,商品ID=1001,数量=2

        // 2. 减少库存(远程调用)
        inventoryClient.decreaseInventory(1001L, 2);
    }
}

第5步:编写 InventoryServiceFeignClient.java(调用库存服务)

@FeignClient(name = "inventory-service")
public interface InventoryServiceFeignClient {
    @PostMapping("/inventory/decrease")
    void decreaseInventory(@RequestParam("productId") Long productId,
                           @RequestParam("count") int count);
}

第6步:库存服务的 Controller 和 Service 示例

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

    @Autowired
    private InventoryService inventoryService;

    @PostMapping("/decrease")
    public void decreaseInventory(@RequestParam Long productId, @RequestParam int count) {
        inventoryService.decrease(productId, count);
    }
}

@Service
public class InventoryService {

    @Autowired
    private InventoryMapper inventoryMapper;

    public void decrease(Long productId, int count) {
        inventoryMapper.updateStock(productId, count);
    }
}

测试一下!

  1. 启动 Seata Server
  2. 启动两个 Spring Boot 服务
  3. 访问地址:http://localhost:8080/order/create

如果你看到订单被插入但库存没更新,说明事务回滚生效了!


五、常见问题答疑(FAQ)

Q1:分布式事务对性能影响大吗?

  • :会影响一些,特别是XA模式会加锁,但多数生产环境会选择 TCC 或 Seata 的 AT 模式平衡性能与一致性。

Q2:Seata 是必须的吗?有没有替代方案?

  • :不是必须的,也可以用 RocketMQ 事务消息、或者自研 TCC,但推荐使用成熟组件如 Seata。

Q3:代码中 @GlobalTransactional 是什么作用?

  • :这是 Seata 提供的注解,加上它就能开启一个分布式事务,Seata 会自动帮你处理提交和回滚。

Q4:微服务调用必须用 Feign 吗?

  • :不是的,你也可以使用 Dubbo、Ribbon、RestTemplate,只要能跨服务调用都可以结合 Seata。

六、学习建议:下一步我可以怎么学?

恭喜你完成了第一课!接下来你可以继续深入以下几个方向:

1. 学习 Seata 的更多模式(AT、TCC、Saga)

2. 学习 RocketMQ 实现最终一致性事务

  • 结合 Kafka、RabbitMQ 等消息队列异步处理事务

3. 学习 CAP 定理和 BASE 理论

  • 帮你理解分布式系统的取舍原则

4. 深入阅读源码:从官方 GitHub 上看 Seata 的源码结构


写在最后:

作为一名老师,我常常告诉初学者一句话:

“不要怕难的技术,只要你不放弃,早晚都能学会。”

分布式事务虽然看起来复杂,但只要你一步一步去动手写、去调试,它其实并没有想象中那么难。

加油吧,未来的大神!💪


📌 文章字数:约2087字

评论 0

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