【SpringBoot】微服务学习笔记七:微服务中异步调用数据提交数据库的问题_请描述您在使用springboot进行微服务开发时,如何处理服务之间的调用和数据交

    String content = ((StringBuilder) map.get("content")).toString();
    //2.2调用腾讯云进行文本检测
    Boolean THandleResult = handleTextScan(content, wmNews);
    if(!THandleResult) return;

    //3.检测图片
    //3.1提取图片
    List<String> imageUrl = (List<String>) 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](https://img-blog.csdnimg.cn/8fb3b6c21d0c4a0cb2852cefa5d7a565.png)


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



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


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


### 3.问题剖析


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


![c2c6fd6f46a4463f8134c4756f8aed74.png](https://img-blog.csdnimg.cn/c2c6fd6f46a4463f8134c4756f8aed74.png)


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


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


![c91d984358864ef3a327ddabd21fdd46.png](https://img-blog.csdnimg.cn/c91d984358864ef3a327ddabd21fdd46.png)


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


## 三:问题解决


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


![16ffc7beea4441148d31e5b6e54250a7.png](https://img-blog.csdnimg.cn/16ffc7beea4441148d31e5b6e54250a7.png)


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


![131634801d594f6691abed4983dbc597.png](https://img-blog.csdnimg.cn/131634801d594f6691abed4983dbc597.png)


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






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值