行业资讯 2025年08月6日
0 收藏 0 点赞 784 浏览 7753 个字
摘要 :

文章目录 一、Seata与TCC模式基础介绍 1.1 Seata简介 1.2 TCC模式解析 二、电商系统案例分析 2.1 业务场景与系统架构 2.2 数据库表设计 2.3 服务设计与调用实现 2.4 ……




  • 一、Seata与TCC模式基础介绍
    • 1.1 Seata简介
    • 1.2 TCC模式解析
  • 二、电商系统案例分析
    • 2.1 业务场景与系统架构
    • 2.2 数据库表设计
    • 2.3 服务设计与调用实现
    • 2.4 全局事务发起
  • 三、总结

在微服务架构盛行的当下,分布式事务管理成为开发过程中绕不开的关键难题。今天,我们就借助Seata和TCC模式,并基于Spring Cloud Alibaba框架,通过一个电商案例来深入探讨如何实现分布式事务管理。

一、Seata与TCC模式基础介绍

1.1 Seata简介

Seata(Simple Extensible Autonomous Transaction Architecture)是一款开源的分布式事务解决方案,主要为微服务架构提供高性能且易用的分布式事务支持。它支持多种事务模式,其中TCC(Try-Confirm-Cancel)模式凭借其灵活性和高性能,在互联网场景尤其是电商、金融等领域得到广泛应用。

Seata包含几个核心组件:

  • TC(Transaction Coordinator):即事务协调者,负责对全局事务的状态进行管理,掌控整个事务的走向。
  • TM(Transaction Manager):也就是事务管理器,用于定义全局事务的范围,并负责发起事务的提交或回滚操作。
  • RM(Resource Manager):资源管理器,主要管理分支事务,承担与数据库交互的工作。

1.2 TCC模式解析

TCC模式是一种基于补偿机制的分布式事务模式,整个过程分为三个阶段:

  • Try阶段:尝试执行业务逻辑,这个阶段主要是预留相关资源。以电商场景为例,就是冻结库存,确保后续业务有资源可用。
  • Confirm阶段:确认阶段,用于提交业务逻辑。对应到电商场景,就是真正扣减库存,完成业务操作。
  • Cancel阶段:取消阶段,主要进行回滚操作。比如释放之前冻结的库存,保证数据的一致性。

TCC模式适用于对高并发和高性能有较高要求的场景,通过在业务代码中显式定义补偿逻辑,给予开发者更大的操作灵活性。

二、电商系统案例分析

2.1 业务场景与系统架构

假设我们正在构建一个电商系统,该系统包含以下几个关键微服务:

  • 订单服务(Order Service):负责创建订单,并记录用户相关信息。
  • 库存服务(Inventory Service):主要承担商品库存的管理工作。
  • 支付服务(Payment Service):用于处理用户的支付流程。

在用户下单时,系统需要完成一系列操作:创建订单记录、冻结商品库存、扣款并记录支付状态。只要其中任何一个步骤出现问题,就必须回滚所有操作,以此保证数据的一致性。

2.2 数据库表设计

为了支撑系统功能,设计了以下数据库表:

  • 订单服务表
CREATE TABLE `orders` (
  `id` BIGINT AUTO_INCREMENT PRIMARY KEY,
  `user_id` BIGINT NOT NULL,
  `product_id` BIGINT NOT NULL,
  `quantity` INT NOT NULL,
  `total_amount` DECIMAL(10, 2) NOT NULL,
  `status` VARCHAR(20) NOT NULL DEFAULT \'PENDING\' -- PENDING, CONFIRMED, CANCELLED
);

该表用于存储订单相关信息,包括订单编号、用户ID、商品ID、购买数量、总金额以及订单状态等。

  • 库存服务表
CREATE TABLE `inventory` (
  `id` BIGINT AUTO_INCREMENT PRIMARY KEY,
  `product_id` BIGINT NOT NULL,
  `total_stock` INT NOT NULL,
  `frozen_stock` INT NOT NULL DEFAULT 0
);

此表记录商品库存情况,包含商品ID、总库存数量以及冻结库存数量。

  • 支付服务表
CREATE TABLE `payment` (
  `id` BIGINT AUTO_INCREMENT PRIMARY KEY,
  `order_id` BIGINT NOT NULL,
  `user_id` BIGINT NOT NULL,
  `amount` DECIMAL(10, 2) NOT NULL,
  `status` VARCHAR(20) NOT NULL DEFAULT \'PENDING\' -- PENDING, SUCCESS, FAILED
);

支付服务表主要存储支付相关信息,如订单ID、用户ID、支付金额以及支付状态。

2.3 服务设计与调用实现

我们借助Spring Cloud Alibaba、Seata TCC和Feign来实现服务间的调用。

  1. 订单服务(Order Service):订单服务在整个事务中扮演全局事务发起者的角色,负责协调库存和支付服务。
    • TCC接口定义
public interface OrderTccService {
    @TwoPhaseBusinessAction(name = \"OrderTccAction\", commitMethod = \"confirm\", rollbackMethod = \"cancel\")
    void tryCreate(OrderDTO orderDTO, @BusinessActionContextParameter(paramName = \"orderId\") Long orderId);

    boolean confirm(BusinessActionContext context);

    boolean cancel(BusinessActionContext context);
}

该接口定义了订单服务在TCC模式下的三个核心方法,tryCreate用于尝试创建订单,confirm用于确认订单操作,cancel用于取消订单操作。

- **接口实现**:
@Service
public class OrderTccServiceImpl implements OrderTccService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private InventoryClient inventoryClient;
    @Autowired
    private PaymentClient paymentClient;

    @Override
    @Transactional
    public void tryCreate(OrderDTO orderDTO, Long orderId) {
        Order order = new Order();
        order.setUserId(orderDTO.getUserId());
        order.setProductId(orderDTO.getProductId());
        order.setQuantity(orderDTO.getQuantity());
        order.setTotalAmount(orderDTO.getTotalAmount());
        order.setStatus(\"PENDING\");
        orderMapper.insert(order);

        // 调用库存服务冻结库存
        inventoryClient.freezeStock(order.getProductId(), order.getQuantity());
        // 调用支付服务冻结金额
        paymentClient.freezePayment(order.getId(), order.getTotalAmount());
    }

    @Override
    public boolean confirm(BusinessActionContext context) {
        Long orderId = (Long) context.getActionContext(\"orderId\");
        Order order = orderMapper.selectById(orderId);
        order.setStatus(\"CONFIRMED\");
        orderMapper.updateById(order);
        return true;
    }

    @Override
    public boolean cancel(BusinessActionContext context) {
        Long orderId = (Long) context.getActionContext(\"orderId\");
        Order order = orderMapper.selectById(orderId);
        order.setStatus(\"CANCELLED\");
        orderMapper.updateById(order);
        return true;
    }
}

在实现类中,tryCreate方法在创建订单记录后,调用库存服务和支付服务进行资源预留。confirmcancel方法分别用于处理订单确认和取消时的逻辑。

- **Feign客户端**:
@FeignClient(name = \"inventory-service\")
public interface InventoryClient {
    @PostMapping(\"/inventory/freeze\")
    void freezeStock(@RequestParam(\"productId\") Long productId, @RequestParam(\"quantity\") Integer quantity);
}

@FeignClient(name = \"payment-service\")
public interface PaymentClient {
    @PostMapping(\"/payment/freeze\")
    void freezePayment(@RequestParam(\"orderId\") Long orderId, @RequestParam(\"amount\") BigDecimal amount);
}

Feign客户端用于实现订单服务与库存服务、支付服务之间的远程调用。

  1. 库存服务(Inventory Service):库存服务主要实现冻结、确认和取消库存的逻辑。
    • TCC接口
public interface InventoryTccService {
    @TwoPhaseBusinessAction(name = \"InventoryTccAction\", commitMethod = \"confirm\", rollbackMethod = \"cancel\")
    void freezeStock(@BusinessActionContextParameter(paramName = \"productId\") Long productId, Integer quantity);

    boolean confirm(BusinessActionContext context);

    boolean cancel(BusinessActionContext context);
}

定义了库存服务在TCC模式下的相关方法。

- **接口实现**:
@RestController
@RequestMapping(\"/inventory\")
public class InventoryTccServiceImpl implements InventoryTccService {
    @Autowired
    private InventoryMapper inventoryMapper;

    @Override
    @PostMapping(\"/freeze\")
    @Transactional
    public void freezeStock(Long productId, Integer quantity) {
        Inventory inventory = inventoryMapper.selectByProductId(productId);
        if (inventory.getTotalStock() - inventory.getFrozenStock() < quantity) {
            throw new RuntimeException(\"Insufficient stock\");
        }
        inventory.setFrozenStock(inventory.getFrozenStock() + quantity);
        inventoryMapper.updateById(inventory);
    }

    @Override
    public boolean confirm(BusinessActionContext context) {
        Long productId = (Long) context.getActionContext(\"productId\");
        Inventory inventory = inventoryMapper.selectByProductId(productId);
        Integer quantity = (Integer) context.getActionContext(\"quantity\");
        inventory.setFrozenStock(inventory.getFrozenStock() - quantity);
        inventory.setTotalStock(inventory.getTotalStock() - quantity);
        inventoryMapper.updateById(inventory);
        return true;
    }

    @Override
    public boolean cancel(BusinessActionContext context) {
        Long productId = (Long) context.getActionContext(\"productId\");
        Inventory inventory = inventoryMapper.selectByProductId(productId);
        Integer quantity = (Integer) context.getActionContext(\"quantity\");
        inventory.setFrozenStock(inventory.getFrozenStock() - quantity);
        inventoryMapper.updateById(inventory);
        return true;
    }
}

freezeStock方法用于检查库存并冻结相应数量的库存,confirmcancel方法分别处理确认和取消操作时的库存变化。

  1. 支付服务(Payment Service):支付服务负责处理支付冻结和扣款操作。
    • TCC接口
public interface PaymentTccService {
    @TwoPhaseBusinessAction(name = \"PaymentTccAction\", commitMethod = \"confirm\", rollbackMethod = \"cancel\")
    void freezePayment(@BusinessActionContextParameter(paramName = \"orderId\") Long orderId, BigDecimal amount);

    boolean confirm(BusinessActionContext context);

    boolean cancel(BusinessActionContext context);
}

定义了支付服务在TCC模式下的操作方法。

- **接口实现**:
@RestController
@RequestMapping(\"/payment\")
public class PaymentTccServiceImpl implements PaymentTccService {
    @Autowired
    private PaymentMapper paymentMapper;

    @Override
    @PostMapping(\"/freeze\")
    @Transactional
    public void freezePayment(Long orderId, BigDecimal amount) {
        Payment payment = new Payment();
        payment.setOrderId(orderId);
        payment.setAmount(amount);
        payment.setStatus(\"PENDING\");
        paymentMapper.insert(payment);
    }

    @Override
    public boolean confirm(BusinessActionContext context) {
        Long orderId = (Long) context.getActionContext(\"orderId\");
        Payment payment = paymentMapper.selectByOrderId(orderId);
        payment.setStatus(\"SUCCESS\");
        paymentMapper.updateById(payment);
        return true;
    }

    @Override
    public boolean cancel(BusinessActionContext context) {
        Long orderId = (Long) context.getActionContext(\"orderId\");
        Payment payment = paymentMapper.selectByOrderId(orderId);
        payment.setStatus(\"FAILED\");
        paymentMapper.updateById(payment);
        return true;
    }
}

freezePayment方法用于冻结支付金额,confirmcancel方法分别处理支付成功和取消时的逻辑。

2.4 全局事务发起

在订单服务的控制器中,使用@GlobalTransactional注解来发起全局事务:

@RestController
@RequestMapping(\"/order\")
public class OrderController {
    @Autowired
    private OrderTccService orderTccService;

    @PostMapping(\"/create\")
    @GlobalTransactional
    public String createOrder(@RequestBody OrderDTO orderDTO) {
        orderTccService.tryCreate(orderDTO, null);
        return \"Order created successfully\";
    }
}

当用户发起创建订单请求时,@GlobalTransactional注解会开启一个全局事务,确保整个下单流程的数据一致性。

三、总结

通过Seata的TCC模式,我们成功在电商系统中实现了分布式事务管理。在这个过程中,订单服务作为TM发起全局事务,库存服务和支付服务作为RM分别处理各自的资源预留和补偿逻辑。借助Spring Cloud Alibaba的Feign完成服务间的调用,利用MyBatis实现数据库操作。这种方案在高并发场景下,既保证了数据的一致性,又具备良好的性能表现,为电商系统等分布式应用的开发提供了可靠的事务管理方式。

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/10417.html

管理员

相关推荐
2025-08-06

文章目录 一、Reader 接口概述 1.1 什么是 Reader 接口? 1.2 Reader 与 InputStream 的区别 1.3 …

988
2025-08-06

文章目录 一、事件溯源 (一)核心概念 (二)Kafka与Golang的优势 (三)完整代码实现 二、命令…

465
2025-08-06

文章目录 一、证明GC期间执行native函数的线程仍在运行 二、native线程操作Java对象的影响及处理方…

348
2025-08-06

文章目录 一、事务基础概念 二、MyBatis事务管理机制 (一)JDBC原生事务管理(JdbcTransaction)…

456
2025-08-06

文章目录 一、SnowFlake算法核心原理 二、SnowFlake算法工作流程详解 三、SnowFlake算法的Java代码…

517
2025-08-06

文章目录 一、本地Jar包的加载操作 二、本地Class的加载方法 三、远程Jar包的加载方式 你知道Groo…

832
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号