使用Seata处理分布式事务

本文介绍了如何使用Seata处理分布式事务,以电商购买场景为例,展示了Seata的AT模式在异常情况下能确保事务的原子性。在订单创建、库存扣减和账户扣款过程中,当发生异常时,事务能够正确回滚,保持数据一致性。文中还给出了关键代码实现,强调了Seata在并发量低的场景下的适用性。
摘要由CSDN通过智能技术生成

使用Seata处理分布式事务

Gitee地址:https://gitee.com/yuyuuyuy/micro-mall



前言

电商项目中经常会遇到需要处理分布式事务场景。比如用户买东西,会进行下订单,扣减库存,扣用户账号余额等系列操作,在单服务器下,我们可以利用本地事务保证这一系列操作的原子性,然而,在分布式的情况下,事务就失效了。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处理分布式事务的例子。但该种方案不适合高并发的场景,比较适合处理并发量低的场景。高并发下,还是建议使用柔性事务解决方案,允许暂时的不一致性,保证最终一致性即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值