栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

使用Seata处理分布式事务

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用Seata处理分布式事务

使用Seata处理分布式事务

文章目录
  • 使用Seata处理分布式事务
  • 前言
  • 一、Seata架构
  • 二、效果展示
  • 三、代码实现
  • 总结


前言

电商项目中经常会遇到需要处理分布式事务场景。比如用户买东西,会进行下订单,扣减库存,扣用户账号余额等系列操作,在单服务器下,我们可以利用本地事务保证这一系列操作的原子性,然而,在分布式的情况下,事务就失效了。Seata就是处理这类问题的开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。使用到的技术有:Seata,Dubbo,mysql


一、Seata架构

以下是官网提供的Seata架构图

TC (Transaction Coordinator) - 事务协调者
维护全局和分支事务的状态,驱动全局事务提交或回滚。

TM (Transaction Manager) - 事务管理器
定义全局事务的范围:开始全局事务、提交或回滚全局事务。

RM (Resource Manager) - 资源管理器
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

AT模式:
一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
二阶段:提交异步化,非常快速地完成。回滚通过一阶段的回滚日志进行反向补偿。

二、效果展示

这里使用Seata提供的AT事务模式。场景说明:用户购买商品,调用库存服务扣减库存和订单服务生成订单,订单服务调用账户服务扣余额,要保证这一系列操作的原子性,要么全成功,要么全失败。

本例子中在订单生成完毕,以及账户扣减余额之后,加入10/0这样的有问题的代码,看已执行成功的操作是否会全部回滚

Begin new global transaction表明开始了分布式事务
Branch Rollbacked result: PhaseTwo_Rollbacked表示第二阶段出现异常,回滚成功。
再抛出异常前让程序等待5s,就可以看到回滚日志了。回滚日志如下:

查看数据库,发现数据没发生任何变化,回滚成功,分布式事务生效

三、代码实现

购买商品,在事务入口处添加 @GlobalTransactional注解开启全局事务

    
    @GlobalTransactional
    public void purchase(String userId, String commodityCode, int orderCount) throws InterruptedException {
        //库存服务减库存
        storageService.deduct(commodityCode, orderCount);
        //生成新订单
        orderService.create(userId, commodityCode, orderCount);
    }

库存服务,扣减库存

    @Transactional
    public void deduct(String commodityCode, int count) {
        storageMapper.deduct(commodityCode,count);
    }

生成订单

    @Transactional
    public int create(String userId, String commodityCode, int orderCount)  {
        int orderMoney = calculate(commodityCode, orderCount);
        accountService.debit(userId, orderMoney);
        OrderTbl order = new OrderTbl();
        order.setUserId(userId);
        order.setCommodityCode(commodityCode);
        order.setCount(orderCount);
        order.setMoney(orderMoney);
        orderMapper2.insertSelective(order);
//        解开下面注释,测试Seata分布式事务回滚
//        boolean flag=false;
//        if (!flag) {
//            throw new RuntimeException("测试抛异常后,分布式事务回滚!");
//        }
        // INSERT INTO orders ...
        return 1;
    }
    private int calculate(String commodityCode, int orderCount) {
        //TODO 拿到该商品的价格,乘以该商品的数量,假设该商品的价格为10
        return 10*orderCount;
    }

账户服务,扣减余额

    @Transactional
    public void debit(String userId, int money) {
        accountMapper.debit(userId,money);
    }

其中,微服务之间的远程调用使用Dubbo来实现
使用@DubboService来暴露服务

@DubboService
@Service
public class AccountServiceImpl implements AccountService {
//账号服务
}

使用@DubboReference来引入服务

    @DubboReference
    AccountService accountService;
总结

例如:以上就是使用Seata处理分布式事务的例子。但该种方案不适合高并发的场景,比较适合处理并发量低的场景。高并发下,还是建议使用柔性事务解决方案,允许暂时的不一致性,保证最终一致性即可。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/839354.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号