前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >聊聊如何在spring事务中正确进行远程调用

聊聊如何在spring事务中正确进行远程调用

作者头像
lyb-geek
发布2022-01-07 09:36:39
6910
发布2022-01-07 09:36:39
举报
文章被收录于专栏:Linyb极客之路

01

前言

最近和朋友聊天,他说他承接的外包项目遇到了分布式事务问题,问我有没啥解决方案,我本可以直接跟他说,分布式事务方案网上一大堆,什么tcc、可靠消息一致性、最大努力通知之类的,直接网上找个试下,比如直接用阿里的seata。但我并没有这么做,因为分布式事务,本来就是一个很复杂的课题,真正落地的时候,会发现有时候是多种分布式方案一起混用,而非一种方案走到黑。

因此我就跟他说,能不用分布式事务,就尽量不用,后来我就问了一下他的业务场景,场景也不是很复杂,就是邀请好友注册,然后可以增加积分,朋友实现逻辑的伪代码大概如下

代码语言:javascript
复制
@Transactional(rollbackFor = Exception.class)
    public Boolean inviteUser(..){
        userService.add(..);
        integralService.addIntegration(..,20)
    }

其中integralService是一个远程积分服务,20为增加的积分值。这代码乍一看是没问题,我想可能很多朋友都会这么写。后边我就问朋友说你们这个业务场景是否允许如下场景

  • 允不允许邀请的用户入库成功,而积分入库失败?
  • 允不允许邀请的用户入库失败,而积分入库成功?

朋友思考了一下,说第二种不允许,第一种方式可以通过补偿的方式增加积分。

现在我们回过头来看这段代码,我抛出以下两个问题,看文章的朋友可以思考下

  • 如果添加积分请求耗时特别长,这段代码有没有问题?
  • 如果添加积分因为网络抖动原因出了异常,这段代码有没有问题?

这边说下我的想法

  • 耗时过长,会导致长事务的发生,在并发场景下,可能会导致数据库连接得不到释放
  • 网络抖动出了异常,可能会导致用户服务的添加逻辑进行回滚

解决耗时过长,有些朋友可能想到可以采用异步的方式,积分抖动异常,可以通过添加熔断机制,比如积分超时没响应,就直接进行熔断

今天我再说一种方案,就是在事务提交后再进行调用,罗里吧嗦一大堆,才刚要进入正题,哈哈

02

如何在spring的事务中正确的进行远程调用

通过spring的事务同步管理器

这个是个什么鬼,这是我直译,它的真身是长如下

代码语言:javascript
复制
org.springframework.transaction.support.TransactionSynchronizationManager

这玩意有啥用,可以利用它注册一个事务同步器,这个事务同步器,可以允许在事务提交后,做一些事情,核心代码如下

代码语言:javascript
复制
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                //做你想做的业务
            }
        });

看了代码,想必大家都知道怎么改造上面邀请用户,添加积分了吧

代码语言:javascript
复制
@Transactional(rollbackFor = Exception.class)
    public Boolean inviteUser(..) {
        userService.add(..);
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                integralService.addIntegration(..,20)
            }
        });

但大家发现没有,每次都要写这么一坨代码,看着是不是很恶心,有没有什么改造的方案。答案有的,通过注解+aop来整合实现,具体实现逻辑,可以查看下面demo链接中的

代码语言:javascript
复制
com.github.lybgeek.transactional

我这边就不贴具体代码了,为什么不贴,是因为我要介绍另外一种方案,就是基于spring的事件驱动实现

通过TransactionalEventListener注解+ApplicationEventPublisher

这是spring的事件驱动实现,或者说是观察者实现方式,不过TransactionalEventListener注解是spring4.2版本之后才提供的注解

通过这种方式如何改造上面邀请用户,添加积分的实现?

01

在邀请用户注册方法中,进行事件发布

伪代码如下

代码语言:javascript
复制
@Transactional(rollbackFor = Exception.class)
  public Boolean inviteUser(..) {
        userService.add(..);
         applicationEventPublisher.publishEvent(..);
        });

02

编写一个事务监听器,并在里面触发添加积分实现 伪代码如下

代码语言:javascript
复制
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void addIntegration(..){
        integralService.addIntegration(..,20)
    }

这边有个细节点要注意,就是监听事件的参数要和发布的参数一致

03

实现核心源码

代码语言:javascript
复制
@Override
  public void onApplicationEvent(ApplicationEvent event) {
    if (TransactionSynchronizationManager.isSynchronizationActive()) {
      TransactionSynchronization transactionSynchronization = createTransactionSynchronization(event);
      TransactionSynchronizationManager.registerSynchronization(transactionSynchronization);
    }
    else if (this.annotation.fallbackExecution()) {
      if (this.annotation.phase() == TransactionPhase.AFTER_ROLLBACK && logger.isWarnEnabled()) {
        logger.warn("Processing " + event + " as a fallback execution on AFTER_ROLLBACK phase");
      }
      processEvent(event);
    }
    else {
      // No transactional event execution at all
      if (logger.isDebugEnabled()) {
        logger.debug("No transaction is active - skipping " + event);
      }
    }
  }

不知道大家发现没有,他本质上还是使用了TransactionSynchronizationManager,只是对他再一次进行封装

03

总结

在和朋友交流后,发现他们那个外包项目开发人员就只有三个,然后服务拆分了10来个,我就问他说这个外包项目业务有很复杂吗,他说其实还好,我就问他说业务不复杂,开发人员也不多,为什么不用单体架构,而要用微服务。他给我的答案是甲方爸爸觉得他们项目未来会承载很大的业务量,所以必须得用微服务,而且现在的主流技术栈是微服务。听到这个答复,我是该说是过度设计还是高瞻远瞩呢?技术日新月异,鬼知道后面会不会出现更厉害的东西,架构从来都不是一步到位,而是逐步演进

04

demo链接

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-transation-after-commit

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-05-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linyb极客之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 01
  • 02
  • 03
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档