欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺析SpringBoot微服務(wù)中異步調(diào)用數(shù)據(jù)提交數(shù)據(jù)庫的問題

 更新時間:2022年07月25日 14:28:23   作者:趙四司機  
這篇文章主要介紹了SpringBoot微服務(wù)中異步調(diào)用數(shù)據(jù)提交數(shù)據(jù)庫的問題,今天本文涉及到的知識點不難,都是很簡單的crud操作,本文結(jié)合實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下

前言:

1.前面基于Springboot的單體項目介紹已經(jīng)完結(jié)了,至于項目中的其他功能實現(xiàn)我這里就不打算介紹了,因為涉及的知識點不難,而且都是簡單的CRUD操作,假如有興趣的話可以私信我我再看看要不要寫幾篇文章做個介紹。

2.完成上一階段的學(xué)習(xí),我就投入到了微服務(wù)的學(xué)習(xí)當(dāng)中,所用教程為B站上面黑馬的微服務(wù)教程。由于我的記性不是很好,所以對于新事物的學(xué)習(xí)我比較喜歡做筆記以加強理解,在這里我會將筆記的重點內(nèi)容做個總結(jié)發(fā)布到“微服務(wù)學(xué)習(xí)”筆記欄目中。我是趙四,一名有追求的程序員,希望大家能多多支持,能給我點個關(guān)注就更好了。

一: 同步&異步

1.同步與異步的概念

在進行問題探討之前,我們有必要先了解一下什么是同步什么是異步。先來個官方點的說法:同步和異步關(guān)注的是消息通信機制 (synchronous communication/ asynchronous communication)。同步,就是調(diào)用某個東西是,調(diào)用方得等待這個調(diào)用返回結(jié)果才能繼續(xù)往后執(zhí)行。異步,和同步相反 調(diào)用方不會理解得到結(jié)果,而是在調(diào)用發(fā)出后調(diào)用者可用繼續(xù)執(zhí)行后續(xù)操作,被調(diào)用者通過狀體來通知調(diào)用者,或者通過回掉函數(shù)來處理這個調(diào)用。

可能你會就得有點懵?下面我們舉個簡單點的例子:就好像你去買水果,發(fā)現(xiàn)水果賣完了,這時候水果還在來的路上,你選擇等待,直到水果到了你買完才離開,這就是同步;而你知道水果賣完了,你跟店家說你要買什么然后店家到時候給你送貨上門,你只是跟店家說了一句之后便離開去干其他事情了,這就是異步。

2.同步方法調(diào)用&異步方法調(diào)用

前面介紹完同步和異步的概念之后,我們要把它代入到我們的代碼世界里面,在代碼世界里面,同步和異步一般體現(xiàn)在方法調(diào)用和http請求(ajax發(fā)送異步請求)上面,這里主要介紹方法調(diào)用。

2.1:同步方法調(diào)用

所謂同步方法調(diào)用,就是一個方法A調(diào)用方法B之后,方法A必須要等待方法B執(zhí)行完才能繼續(xù)執(zhí)行,要是方法B沒執(zhí)行完方法A就必須一直等待,見下圖:

2.2:異步方法調(diào)用

異步方法調(diào)用指的是當(dāng)方法A調(diào)用方法B之后,方法A不需要等待方法B執(zhí)行完畢再去干別的事,方法A只需要發(fā)起調(diào)用請求之后便繼續(xù)執(zhí)行自己的程序,方法B在另外一個線程里面執(zhí)行,兩者互不干擾,見下圖:

二:問題引入

1.功能需求

程序中我要實現(xiàn)的功能是作者發(fā)布文章之后線程A完成文章的保存工作,且在線程A里面要開啟異步調(diào)用線程B實現(xiàn)文章的審核功能。部分代碼如下

@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<String,Object> map = getTextAndImages(wmNews);
 
        //2.檢測文本
        //2.1提取文本
        String content = ((StringBuilder) map.get("content")).toString();
        //2.2調(diào)用騰訊云進行文本檢測
        Boolean THandleResult = handleTextScan(content, wmNews);
        if(!THandleResult) return;
 
        //3.檢測圖片
        //3.1提取圖片
        List<String> imageUrl = (List<String>) map.get("images");
        //3.2調(diào)用騰訊云對圖片進行檢測
        Boolean IHandleresult = handleImageScan(imageUrl, wmNews);
        if(!IHandleresult) return;
 
        //4,審核成功
        //4.1保存文章
        log.info("檢測到文章無違規(guī)內(nèi)容");
        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.參數(shù)校驗
    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設(shè)置封面圖片
    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())) {
        //直接保存結(jié)束
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
 
    //4.不是草稿
    //4.1保存文章圖片素材與文章關(guān)系
    //4.1.1提取圖片素材列表
    List<String> imagesList = getImagesList(dto);
    //4.1.2保存
    saveRelatedImages(imagesList,wmNews.getId(),WemediaConstants.WM_CONTENT_REFERENCE);
    //4.2保存封面圖片和文章關(guān)系
    saveRelatedCover(dto,imagesList,wmNews);
 
    //5.審核文章(異步調(diào)用)
    wmAutoScanService.AutoScanTextAndImage(wmNews.getId());
    
    return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}

2.問題引出

代碼看著沒有什么問題,但是運行起來之后發(fā)現(xiàn)出現(xiàn)以下錯誤:

這是手動拋出的異常,拋出位置為:

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

可以看到查詢出的文章對象為空。

3.問題剖析

既然這里出現(xiàn)空對象,那么是不是因為沒有進行數(shù)據(jù)插入呢?查看前面的日志信息,可以看到確實插入了一條數(shù)據(jù):

接下來進行的操作時查詢該條數(shù)據(jù),查看MySQL日志信息:

可以看到查出的數(shù)據(jù)為空,那么為什么會出現(xiàn)這樣的情況呢?要注意的是,這里開啟了異步方法調(diào)用,這時候線程A是負(fù)責(zé)將數(shù)據(jù)保存的,而線程B是負(fù)責(zé)對文章進行審核的,而且線程A開啟了事務(wù)支持,會不會是因為這兩個方法都被認(rèn)為是同一個事務(wù)所以事務(wù)還沒結(jié)束線程B查詢不到數(shù)據(jù)呢?這應(yīng)該是不可能的,因為要想實現(xiàn)jdbc事務(wù), 就必須是在同一個連接對象中操作,而我們可以看到,在進行查詢操作時候是創(chuàng)建了一個新的連接的:

那這時候只有一種可能,就是由于A開啟了事務(wù),這時候B線程是異步執(zhí)行的,只要線程A還沒有執(zhí)行完畢,數(shù)據(jù)就不會被提交到數(shù)據(jù)庫中,這時候線程B嘗試去數(shù)據(jù)庫中獲取該數(shù)據(jù)顯然是獲取不到的。

三:問題解決

有了以上假設(shè),實踐是檢驗真理的唯一標(biāo)準(zhǔn),下面通過調(diào)試來檢驗,首先在線程A上加上一句日志打印信息,看看線程B執(zhí)行時線程A是否執(zhí)行完畢(關(guān)系到數(shù)據(jù)時候已經(jīng)提交)。通過斷點進行調(diào)試:

可以看到這時候是能夠獲取到數(shù)據(jù)的,那么假如我在查詢之前讓線程休眠0.5秒呢?

可以看到這時候成功獲取到數(shù)據(jù),說明就是跟數(shù)據(jù)提交時間有關(guān)。

相關(guān)文章

  • SpringBoot實現(xiàn)多數(shù)據(jù)源配置的示例詳解

    SpringBoot實現(xiàn)多數(shù)據(jù)源配置的示例詳解

    這篇文章主要為大家詳細(xì)介紹了SpringBoot實現(xiàn)多數(shù)據(jù)源配置的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-12-12
  • 基于Java代碼配置MyBatis Generator

    基于Java代碼配置MyBatis Generator

    這篇文章主要介紹了基于Java代碼配置MyBatis Generator,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-06-06
  • 淺析java快速排序算法

    淺析java快速排序算法

    這篇文章主要介紹了淺析java快速排序算法,需要的朋友可以參考下
    2015-02-02
  • Java實現(xiàn)鏈棧的示例代碼

    Java實現(xiàn)鏈棧的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何使用鏈?zhǔn)酱鎯Y(jié)構(gòu)來實現(xiàn)棧,也就是鏈棧的實現(xiàn),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2022-11-11
  • Java判斷本機IP地址類型的方法

    Java判斷本機IP地址類型的方法

    Java判斷本機IP地址類型的方法,需要的朋友可以參考一下
    2013-03-03
  • SpringBoot如何進行業(yè)務(wù)校驗實例詳解

    SpringBoot如何進行業(yè)務(wù)校驗實例詳解

    這篇文章主要給大家介紹了關(guān)于SpringBoot如何進行業(yè)務(wù)校驗的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2022-01-01
  • SpringBoot使用Prometheus實現(xiàn)監(jiān)控

    SpringBoot使用Prometheus實現(xiàn)監(jiān)控

    在當(dāng)今的軟件開發(fā)世界中,監(jiān)控是至關(guān)重要的一部分,本文主要介紹了如何在Spring Boot應(yīng)用程序中使用Prometheus進行監(jiān)控,以幫助大家更好地理解和管理您的應(yīng)用程序,有需要的可以參考下
    2023-10-10
  • java正則表達(dá)式的簡單運用

    java正則表達(dá)式的簡單運用

    這篇文章主要為大家詳細(xì)介紹了java正則表達(dá)式的簡單運用,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • SpringBoot打包發(fā)布到linux上(centos 7)的步驟

    SpringBoot打包發(fā)布到linux上(centos 7)的步驟

    這篇文章主要介紹了SpringBoot打包發(fā)布到linux上(centos 7)的步驟,幫助大家更好的理解和使用springboot框架,感興趣的朋友可以了解下
    2020-12-12
  • 詳解Java的線程的優(yōu)先級以及死鎖

    詳解Java的線程的優(yōu)先級以及死鎖

    這篇文章主要介紹了詳解Java的線程的優(yōu)先級以及死鎖,線程是Java編程學(xué)習(xí)中的重要知識,需要的朋友可以參考下
    2015-09-09

最新評論