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

Seata入门系列(11)-Seata之TCC模式入门案例

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

Seata入门系列(11)-Seata之TCC模式入门案例

文章目录

前言TCC 案例

1. 环境搭建2. 自定义两个阶段处理逻辑3. 测试4. 总结

前言

Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

TCC 与 Seata AT 事务一样都是两阶段事务,它与 AT 事务的主要区别为:

TCC 对业务代码侵入严重:每个阶段的数据操作都要自己进行编码来实现,事务框架无法自动处理。TCC 效率更高:不必对数据加全局锁,允许多个事务同时操作数据。

接下来分析下Seata 如何使用TCC 模式。

TCC 案例

案例需求:账户服务调用订单和库存服务进行下单操作,保证某个环节异常时,事务能实现全局一致。

1. 环境搭建

参考Seata 专栏搭建三个测试模块,注意这里不需要undo_log 表。

当前主要组件版本为:

spring.boot:2.3.12.RELEASEspring.cloud:Hoxton.SR12spring.cloud.alibaba:2.2.7.RELEASENacos : 2.0.3Seata: 1.4.2mybatis-plus: 3.4.2

2. 自定义两个阶段处理逻辑

TCC 模式,不依赖于底层数据资源的事务支持:

一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。二阶段 commit 行为:调用 自定义 的 commit 逻辑。二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。

因为TCC 需要自定义分支事务处理逻辑,所以我们需要编写一个账户购买商品服务接口,并添加相关注解。

@LocalTCC
public interface AccountTblService extends IService {

    
    @TwoPhaseBusinessAction(name = "prepareBuy", commitMethod = "commit", rollbackMethod = "rollback")
    Object prepareBuy(@BusinessActionContextParameter(paramName = "userId") String userId, String code, @BusinessActionContextParameter(paramName = "count") Long count);

    
    boolean commit(BusinessActionContext actionContext);

    
    boolean rollback(BusinessActionContext actionContext);
}

相关注解说明:

@LocalTCC:作用于服务接口上,表示实现该接口的实现类被 seata 来管理,seata 根据事务的状态,自动调用我们定义的方法,如果没问题则调用 Commit 方法,否则调用 Rollback 方法。@TwoPhaseBusinessAction:该注解用在接口的 Try 方法上,name 为 tcc 方法的 bean 名称,需要全局唯一,一般写方法名即可;commitMethod指定事务成功后的commit方法;rollbackMethod 指定事务失败后的rollback方法。@BusinessActionContextParameter: 该注解用来修饰 Try 方法的入参,被修饰的入参可以在 Commit 方法和 Rollback 方法中通过 BusinessActionContext 获取。

编写接口实现类:

@Service
@Slf4j
public class AccountTblServiceImpl extends ServiceImpl implements AccountTblService {


    @Autowired
    AccountTblMapper accountTblMapper;
    @Autowired
    OrderClint orderClint;
    @Autowired
    StorageApi storageApi;

    @Override
    public Object prepareBuy(String userId, String code, Long count) {
        log.info("开始TCC xid:" + RootContext.getXID());
        //1.查询账户 扣款
        AccountTbl accountTbl = accountTblMapper.selectById(userId);
        AccountTbl accountTbl1 = accountTbl.setMoney(accountTbl.getMoney() - count);
        accountTblMapper.updateById(accountTbl1);
        //2.远程创建订单
        orderClint.insertOrder(accountTbl.getUserId(), code, count);
        //3.远程扣库存
        storageApi.tcc("iphone11", count);
        return "执行完毕!";
    }

    @Override
    public boolean commit(BusinessActionContext actionContext) {
        log.info("xid = " + actionContext.getXid() + "提交成功");
        return true;
    }

    @Override
    public boolean rollback(BusinessActionContext actionContext) {
        // 获取下单时的提交参数
        String userId = actionContext.getActionContext("userId").toString();
        Long count = Long.parseLong(actionContext.getActionContext("count").toString());
        // 进行分支事务扣掉的金额回滚
        AccountTbl accountTbl = accountTblMapper.selectById(userId);
        AccountTbl accountTbl1 = accountTbl.setMoney(accountTbl.getMoney() + count);
        accountTblMapper.updateById(accountTbl1);
        log.info("xid = " + actionContext.getXid() + "进行回滚操作");
        return true;
    }
}

使用@GlobalTransactional开启全局事务:

    @GetMapping("/testTcc")
    @GlobalTransactional
    public Object test() {
        return  accountTblService.prepareBuy("11111111","iphone11",1L);
    }

订单和库存服务也仿照上面书写。

3. 测试

发生异常时,可以看到,TCC模式进行了回滚操作。

4. 总结

上面简单实现了TCC 模式,但是存在很多问题,使用起来也巨麻烦,所以就不再深究了。。。。

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

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

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