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来实现任务的编排。