【SpringBoot】微服务学习笔记七:微服务中异步调用数据提交数据库的问题

【SpringBoot】微服务学习笔记七:微服务中异步调用数据提交数据库的问题主要介绍同步以及异步的区别 同步方法 异步方法的的理解 Springboot 中开启异步调用后数据提交及查询出现的问题

8420b26844034fab91b6df661ae68671.png

个人简介: 

前言:

1.前面基于Springboot的单体项目介绍已经完结了,至于项目中的其他功能实现我这里就不打算介绍了,因为涉及的知识点不难,而且都是简单的CRUD操作,假如有兴趣的话可以私信我我再看看要不要写几篇文章做个介绍。

2.完成上一阶段的学习,我就投入到了微服务的学习当中,所用教程为B站上面黑马的微服务教程。由于我的记性不是很好,所以对于新事物的学习我比较喜欢做笔记以加强理解,在这里我会将笔记的重点内容做个总结发布到“微服务学习”笔记栏目中。我是赵四,一名有追求的程序员,希望大家能多多支持,能给我点个关注就更好了。

一: 同步&异步

1.同步与异步的概念

        在进行问题探讨之前,我们有必要先了解一下什么是同步什么是异步。先来个官方点的说法:同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)。同步,就是调用某个东西是,调用方得等待这个调用返回结果才能继续往后执行。异步,和同步相反 调用方不会理解得到结果,而是在调用发出后调用者可用继续执行后续操作,被调用者通过状体来通知调用者,或者通过回掉函数来处理这个调用。

        可能你会就得有点懵?下面我们举个简单点的例子:就好像你去买水果,发现水果卖完了,这时候水果还在来的路上,你选择等待,直到水果到了你买完才离开,这就是同步;而你知道水果卖完了,你跟店家说你要买什么然后店家到时候给你送货上门,你只是跟店家说了一句之后便离开去干其他事情了,这就是异步。

2.同步方法调用&异步方法调用

        前面介绍完同步和异步的概念之后,我们要把它代入到我们的代码世界里面,在代码世界里面,同步和异步一般体现在方法调用和http请求(ajax发送异步请求)上面,这里主要介绍方法调用。

2.1:同步方法调用

        所谓同步方法调用,就是一个方法A调用方法B之后,方法A必须要等待方法B执行完才能继续执行,要是方法B没执行完方法A就必须一直等待,见下图:

586c97c292cd4b18a258b535b50774a5.png

2.2:异步方法调用

         异步方法调用指的是当方法A调用方法B之后,方法A不需要等待方法B执行完毕再去干别的事,方法A只需要发起调用请求之后便继续执行自己的程序,方法B在另外一个线程里面执行,两者互不干扰,见下图:

830c1efeea4b4ed991d9c38ab65e3d2e.png

二:问题引入

1.功能需求

         程序中我要实现的功能是作者发布文章之后线程A完成文章的保存工作,且在线程A里面要开启异步调用线程B实现文章的审核功能。部分代码如下

@Override @Async //表明这是一个异步方法 public void AutoScanTextAndImage(Integer id) throws TencentCloudSDKException { log.info("开始进行文章审核..."); WmNews wmNews = wmNewsService.getById(id); if(wmNews == null) { throw new RuntimeException("WmAutoScanServiceImpl-文章信息不存在"); } if(wmNews.getStatus().equals(WmNews.Status.SUBMIT.getCode())) { //1.提取文章文本及图片 Map 
  
    map = getTextAndImages(wmNews); //2.检测文本 //2.1提取文本 String content = ((StringBuilder) map.get("content")).toString(); //2.2调用腾讯云进行文本检测 Boolean THandleResult = handleTextScan(content, wmNews); if(!THandleResult) return; //3.检测图片 //3.1提取图片 List 
   
     imageUrl = (List 
    
      ) map.get("images"); //3.2调用腾讯云对图片进行检测 Boolean IHandleresult = handleImageScan(imageUrl, wmNews); if(!IHandleresult) return; //4,审核成功 //4.1保存文章 log.info("检测到文章无违规内容"); ResponseResult responseResult = saveAppArticle(wmNews); if(!responseResult.getCode().equals(200)) { throw new RuntimeException("WmAutoScanServiceImpl-文章审核,保存文章失败"); } //4.2回填article_id wmNews.setArticleId((Long) responseResult.getData()); wmNews.setStatus(WmNews.Status.PUBLISHED.getCode()); wmNews.setReason("审核成功"); wmNewsService.updateById(wmNews); } } 
     
    
  
@Autowired private WmAutoScanService wmAutoScanService; / * 提交文章 * @param dto * @return */ @Override public ResponseResult submitNews(WmNewsDto dto) throws TencentCloudSDKException { //1.参数校验 if(dto == null || dto.getContent().length() == 0) { return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID); } //2.保存或修改文章 //2.1属性拷贝 WmNews wmNews = new WmNews(); BeanUtils.copyProperties(dto,wmNews); //2.2设置封面图片 if(dto.getImages() != null && dto.getImages().size() != 0) { String images = StringUtils.join(dto.getImages(), ","); wmNews.setImages(images); } //2.3封面类型为自动 if(dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)) { wmNews.setType(null); } saveOrUpdateWmNews(wmNews); //3.判断是否为草稿 if(dto.getStatus().equals(WmNews.Status.NORMAL.getCode())) { //直接保存结束 return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS); } //4.不是草稿 //4.1保存文章图片素材与文章关系 //4.1.1提取图片素材列表 List 
  
    imagesList = getImagesList(dto); //4.1.2保存 saveRelatedImages(imagesList,wmNews.getId(),WemediaConstants.WM_CONTENT_REFERENCE); //4.2保存封面图片和文章关系 saveRelatedCover(dto,imagesList,wmNews); //5.审核文章(异步调用) wmAutoScanService.AutoScanTextAndImage(wmNews.getId()); return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS); } 
  

2.问题引出

代码看着没有什么问题,但是运行起来之后发现出现以下错误:

8fb3b6c21d0c4a0cb2852cefa5d7a565.png

 这是手动抛出的异常,抛出位置为:

WmNews wmNews = wmNewsService.getById(id); if(wmNews == null) { throw new RuntimeException("WmAutoScanServiceImpl-文章信息不存在"); }

可以看到查询出的文章对象为空。

3.问题剖析

        既然这里出现空对象,那么是不是因为没有进行数据插入呢?查看前面的日志信息,可以看到确实插入了一条数据:

c2c6fd6f46a4463f8134c4756f8aed74.png

接下来进行的操作时查询该条数据,查看MySQL日志信息:

0a97b55d51aa4f8f9f332c3e139b47d1.png         可以看到查出的数据为空,那么为什么会出现这样的情况呢?要注意的是,这里开启了异步方法调用,这时候线程A是负责将数据保存的,而线程B是负责对文章进行审核的,而且线程A开启了事务支持,会不会是因为这两个方法都被认为是同一个事务所以事务还没结束线程B查询不到数据呢?这应该是不可能的,因为要想实现jdbc事务, 就必须是在同一个连接对象中操作,而我们可以看到,在进行查询操作时候是创建了一个新的连接的:

c91d984358864ef3a327ddabd21fdd46.png

         那这时候只有一种可能,就是由于A开启了事务,这时候B线程是异步执行的,只要线程A还没有执行完毕,数据就不会被提交到数据库中,这时候线程B尝试去数据库中获取该数据显然是获取不到的。

三:问题解决

        有了以上假设,实践是检验真理的唯一标准,下面通过调试来检验,首先在线程A上加上一句日志打印信息,看看线程B执行时线程A是否执行完毕(关系到数据时候已经提交)。通过断点进行调试:

16ffc7beea4441148d31e5b6e54250a7.png

可以看到这时候是能够获取到数据的,那么假如我在查询之前让线程休眠0.5秒呢?

131634801d594f6691abed4983dbc597.png

可以看到这时候成功获取到数据,说明就是跟数据提交时间(也即线程执行顺序)有关,对于这个问题,我们可以使用JDK1.8推出的CompletableFuture来实现任务的编排。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/210212.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 上午8:04
下一篇 2026年3月19日 上午8:04


相关推荐

  • IGMP协议详解_BOOTP协议

    IGMP协议详解_BOOTP协议IGMP协议详解(转载)摘要:文章来自于《TCP/IP详解》卷一第十三章。本文详细介绍IGMP协议原理及实现实例。1、引言  本文将介绍用于支持主机和路由器进行多播的Internet组管理协议(IGMP)。它让一个物理网络上的所有系统知道主机当前所在的多播组。多播路由器需要这些信息以便知道多播数据报应该向哪些接口转发。IGMP在RFC1112中定义[Deering1989].

    2025年11月18日
    4
  • SQL Server 2008R2密钥

    SQL Server 2008R2密钥本文分享 SQLServer200 版本数据库安装介质百度云下载地址及安装密钥

    2026年3月17日
    2
  • html使用vue axios,使用 Vue和axios

    html使用vue axios,使用 Vue和axios昨天写完了博客以后,有人就在我的博客下面留言说现在不是使用了Axios了吗?我赶紧再把Axios的例程给补上,并且做一个更新。其实vue-resource并不复杂,就是不稳定。Vue官方放弃它也是对的,作者是这样子说的最近团队讨论了一下,Ajax本身跟Vue并没有什么需要特别整合的地方,使用fetchpolyfill或是axios、superagent等等都可以起到同等…

    2025年6月29日
    4
  • opencv的sift_opencv sift

    opencv的sift_opencv sift《SIFT原理与源码分析》系列文章索引:http://blog.csdn.net/xiaowei_cqu/article/details/8069548尺度空间理论自然界中的物体随着观测尺度不同有不同的表现形态。例如我们形容建筑物用“米”,观测分子、原子等用“纳米”。更形象的例子比如Google地图,滑动鼠标轮可以改变观测地图的尺度,看到的地图绘制也不同;还有电影中的拉伸镜头等等…

    2022年10月15日
    4
  • Springboot-软件授权License

    Springboot-软件授权License在我们做系统级框架的时候,我们要一定程度上考虑系统的使用版权,不能随便一个人拿去在任何环境都能用,所以我们需要给我们系统做一个授权认证机制,只有上传了我们下发的lic文件并验证通过,才能正常使用。1、Smart-license简介smart-license是一款用于安全加固的开源项目。主要服务于非开源产品、商业软件、具备试用功能的付费软件等,为软件提供授权制的使用方式。1.License,通过smart-license生成的授权文件,导入至要授权使用的软件产品中。2.源数据,需要进行L

    2022年7月26日
    28
  • 分治法大整数乘法c语言,大整数乘法(分治法)「建议收藏」

    分治法大整数乘法c语言,大整数乘法(分治法)「建议收藏」#include#includeusingnamespacestd;intnum(intu)//计算乘数的位数{inti,num;i=1;num=u/10;while(num!=0){u=num;num=u/10;i=i+1;}//cout<returni;}voidMUL(intu,inti,int&w,int&x)//将乘数分治{w=u/(pow…

    2022年6月2日
    35

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号