分布式事务与Seate框架(2)——Seata实践

分布式事务与Seate框架(2)——Seata实践

前言

  在上一篇博文(分布式事务与Seate框架(1)——分布式事务理论)中了解了足够的分布式事务的理论知识后,到了实践部分,在工作中虽然用到了Seata,但是自己却并没有完全实践过,所以自己私下花点时间实践以加深理解,实际上在实践过程中遇到了很多的坑(比如Seata与SpringCloudAlibaba的整合中版本兼容性问题,是个很让人头疼的一块,甚至专门去github提过issue),有时候甚至得跟踪源码进行分析,这也使我加强了对阅读源码的能力。总之都是要code的。本篇博文主要结合实践深入讲解Seata AT模式!

  参考资料《Spring Cloud Alibaba 微服务原理与实战》(PDF电子书资源,有需要的小伙伴可以评论私信我)、官方wiki

  博文中源码已上传至github(https://github.com/Jian0110/learning-cloudalibaba),欢迎小伙伴们star…

 


 

一、实践准备工作

1、框架介绍

实践主要是以“订单-库存-账户”系统演示,主要的框架图如下,图中各个部分充当的分布式事务角色已标明。

    

  具体流程:

  1)用户登录XXX商品购物系统(假设已有账户),

  2)点击购买某个商品,发起创建订单请求;

  3)检查购买商品的库存量,如果不够则创建订单失败提示库存不足;否则锁定该商品—->减少库存—>创建订单;

  4)订单创建成功后点击付款(或直接付款无需点击,实际上整个Demo中下单之后模拟立马支付,并不会点击付款);

  5)如果购买成功则对账户进行余额进行判断,余额足够则进行减扣,余额不够则进行提示说明

  6)返回购买成功失败提示说明。

2、项目结构

项目结构如下:

mvn package打包运行seata服务,即运行TC服务器(这里只展示单机)

初始化Seata库,导入sql脚本

二、代码实践

这里只展示关键代码,全部代码已提交gituhb:,有需要的小伙伴可以自行获取

1、“订单-库存-账户”服务

订单服务:

    TM(microService):seata-order-service

    RM(DB Resources):jdbc:mysql://127.0.0.1:3306/order

OrderService:

@GlobalTransactional // TM开启全局事务
    @Transactional(rollbackFor = Exception.class)
    public void createOrder(Long productId, BigDecimal price){
        // 这里模拟获取的是用户的账户ID
        // 通过上下文获取userId再获取accountId(单个账户)
        Long accountId = 1L; // 假设已经获取到了账户ID

        // 1.rpc调用库存微服务检查库存并减库存操作
        Boolean deductStorageSuccess =  storageFeignClient.deduct(productId);
        if (!deductStorageSuccess) {
            throw new RuntimeException("storage deduct failed!");
        }
        // 2.创建订单
        ProductOrder order =  ProductOrder.builder()
                .productId(productId)
                .accountId(accountId)
                .payAmount(price)
                .build();
        log.info("create order : {}", order);
        // 这里为了模拟回滚,所以先对价格的判断放到了创建订单之后,抛出runtime exception
        if (price.compareTo(BigDecimal.ZERO) < 0) {
            throw new NumberFormatException("product price must greater than zero!");
        }
        orderMapper.insertSelective(order);

        // 3.rpc调用账户微服务对余额检查并扣款操作
        Boolean deductAccountSuccess =  accountFeignClient.deduct(accountId, price);
        if (!deductAccountSuccess) {
            throw new RuntimeException("account deduct failed!");
        }
        // 4. 反馈结果
    }
hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » 分布式事务与Seate框架(2)——Seata实践