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

SpringBoot事務(wù)異步調(diào)用引發(fā)的bug解決

 更新時(shí)間:2023年06月14日 11:10:37   作者:在下uptown  
本文主要介紹了SpringBoot事務(wù)異步調(diào)用引發(fā)的bug解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

日常開發(fā)中有沒有遇到這種場(chǎng)景,save一條數(shù)據(jù)后發(fā)起一次異步調(diào)用,舉個(gè)例子,假設(shè)我們以mysql組件和xxl-job組件為例,創(chuàng)建一條數(shù)據(jù)導(dǎo)出任務(wù),創(chuàng)建后默認(rèn)啟動(dòng)任務(wù)。那么邏輯可能大致為三步。

  • 創(chuàng)建導(dǎo)出任務(wù)(DB.EXPORT_TASK)
  • 創(chuàng)建導(dǎo)出任務(wù)歷史記錄(DB.EXPORT_TASK_HISTORY)
  • 觸發(fā)導(dǎo)出任務(wù)(XXL-JOB)

因?yàn)樾枰瑫r(shí)要?jiǎng)?chuàng)建導(dǎo)出任務(wù)和導(dǎo)出任務(wù)歷史兩條記錄,所以代碼中需要通常要添加事務(wù)

@Service
public class TaskService {
? ? @Transactional(rollbackFor = Exception.class)
? ? public String saveExportTask() {
? ? ? ? // 1. save export task
? ? ? ? // 2. save export task history?
? ? ? ? // 3. execute xxl-job
? ? }
}

外層controller層只需要調(diào)用service的方法即可

@RestController
public class TaskController {
    @Resource TaskService taskService;
    @PostMapping
    public String save() {
        taskService.saveExportTask();
    }
}

我們使用了xxl-job去觸發(fā)任務(wù)是一個(gè)異步調(diào)用的過程,當(dāng)xxl-job回調(diào)執(zhí)行器去執(zhí)行時(shí)可能需要根據(jù)job_id獲取到導(dǎo)出任務(wù)的配置,通過查詢db獲取任務(wù)詳情,比如導(dǎo)出地址了,導(dǎo)出規(guī)范等等。
看似非常和諧的場(chǎng)面,實(shí)際執(zhí)行起來則會(huì)出現(xiàn)任務(wù)不存在的問題。問題的根源其實(shí)也很好理解,就是因?yàn)樵诋惒椒椒ɡ镒隽送降氖戮蜁?huì)出現(xiàn)這種問題,當(dāng)?shù)谝徊經(jīng)]有執(zhí)行完,第三步的回調(diào)方法已經(jīng)到執(zhí)行器了,也就是說一個(gè)任務(wù)還沒存到數(shù)據(jù)庫(kù),執(zhí)行這個(gè)任務(wù)時(shí)去數(shù)據(jù)庫(kù)查該任務(wù)的明細(xì)肯定會(huì)報(bào)任務(wù)不存在異常了。
那么如何解決呢。

代碼拆分

最簡(jiǎn)單的一個(gè)方案,web應(yīng)用通常劃分為controller、service、dao層那么幾層,業(yè)務(wù)邏輯按規(guī)范寫在service層,我們把發(fā)起異步調(diào)用的方法挪到controller層,service只做數(shù)據(jù)庫(kù)操作,servcie執(zhí)行完事務(wù)提交完,再同步發(fā)起異步調(diào)用豈不就繞開了這個(gè)問題。

@RestController
public class TaskController {
    @Resource TaskService taskService;
    @PostMapping
    public String save() {
        taskService.saveExportTask();
        // 3. execute xxl-job
    }
}

如果秉持著代碼和人有一個(gè)能跑就行的原則,此時(shí)已經(jīng)結(jié)束戰(zhàn)斗了,對(duì)于秉持著該原則且有點(diǎn)代碼潔癖同學(xué)頂多也就是把觸發(fā)任務(wù)的動(dòng)作封裝到一個(gè)觸發(fā)service里調(diào)用。

TransactionSynchronizationManager事務(wù)回調(diào)

當(dāng)然還是有很多同學(xué)對(duì)待技術(shù)是追求極致精神的,那么有沒有優(yōu)雅的方式去解決這個(gè)問題,那就要看springboot的事務(wù)回調(diào)能力了。

TransactionSynchronizationManager 事務(wù)同步器,從new TransactionSynchronization()可實(shí)現(xiàn)的方法上即可管中窺豹可見一斑,我們完全可以通過實(shí)現(xiàn)歇歇方法實(shí)現(xiàn)事務(wù)完成后回調(diào)的邏輯。

直接上代碼舉例子

@Service
public class TaskService {
? ? @Transactional(rollbackFor = Exception.class)
? ? public String saveExportTask() {
? ? ? ? // 1. save export task
? ? ? ? // 2. save export task history?
? ? ? ? TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter(){
? ? ? ? ? ? public void afterCommit(){
? ? ? ? ? ? ? ? System.out.println("commit!!!");
? ? ? ? ? ? ? ? // 3. execute xxl-job
? ? ? ? ? ? }
? ? ? ? });
? ? }
}

這樣一來就可以保證是在事務(wù)結(jié)束之后去執(zhí)行xxl-job的任務(wù)。

@TransactionalEventListener注解要和事務(wù)事件監(jiān)控

TransactionalEventListener,自 Spring 4.2 以來,可以使用基于注釋的配置為提交后事件(或更一般的事務(wù)同步事件,例如回滾)定義偵聽器。本質(zhì)上是基于核心 spring中的事件處理。使用這種方法可以避免對(duì) TransactionSynchronizationManager 的硬編碼。

首先需要自定義監(jiān)聽器

@Component
public class TaskEventListener {
? ?@Autowired
? ?private TaskService taskService;
? ?@TransactionalEventListener
? ?public void handleOrderCreatedEvent(TaskCreatedEvent event) {
? ? ? Task task = event.getTask();
? ? ? // 處理訂單創(chuàng)建事件
? ? ? try {
? ? ? ? ?taskService.processOrder(task);
? ? ? } catch (Exception e) {
? ? ? ? ?// 處理失敗,拋出異常,事務(wù)回滾
? ? ? ? ?throw new RuntimeException(e);
? ? ? }
? ?}
? ?@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
? ?public void handleOrderCompletedEvent(TaskCompletedEvent event) {
? ? ? Task task = event.getTask();
? ? ? // 處理訂單完成事件
? ? ? try {
? ? ? ? ?taskService.sendOrderConfirmationEmail(task);
? ? ? } catch (Exception e) {
? ? ? ? ?// 處理失敗,不影響事務(wù)
? ? ? ? ?e.printStackTrace();
? ? ? }
? ?}
}

定義事件

public class TaskCompletedEvent {
? ?private Task task;
? ?public TaskCompletedEvent(Task task) {
? ? ? this.task = task;
? ?}
? ?public Task getTask() {
? ? ? return task;
? ?}
}

@TransactionalEventListener注解要和@Transactional注解配合使用,確保在事務(wù)完成后才會(huì)觸發(fā)回調(diào)方法。@TransactionalEventListener注解也可以指定回調(diào)方法的觸發(fā)時(shí)機(jī),可以選擇在事務(wù)提交后觸發(fā)(默認(rèn))或在事務(wù)回滾后觸發(fā)。

到此這篇關(guān)于SpringBoot事務(wù)異步調(diào)用引發(fā)的bug解決的文章就介紹到這了,更多相關(guān)SpringBoot事務(wù)異步調(diào)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java反射如何有效的修改final屬性值詳解

    Java反射如何有效的修改final屬性值詳解

    最近在工作中遇到一個(gè)需求,要利用反射對(duì)修飾符為final的成員變量進(jìn)行修改,所以這篇文章主要給大家介紹了關(guān)于Java反射如何有效的修改final屬性值的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)需要的朋友可以參考下。
    2017-08-08
  • Java命名規(guī)則詳細(xì)總結(jié)

    Java命名規(guī)則詳細(xì)總結(jié)

    Class名應(yīng)是首字母大寫的名詞。命名時(shí)應(yīng)該使其簡(jiǎn)潔而又具有描述性。異常類的命名,應(yīng)以Exception結(jié)尾。Interface的命名規(guī)則與Class相同
    2013-10-10
  • Java模擬新浪微博登陸抓取數(shù)據(jù)

    Java模擬新浪微博登陸抓取數(shù)據(jù)

    本文主要介紹了Java模擬新浪微博登陸抓取數(shù)據(jù)的實(shí)現(xiàn)方法。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-02-02
  • 深入理解Java對(duì)象復(fù)制

    深入理解Java對(duì)象復(fù)制

    使用任何已有的工具,都沒有直接使用 get set 方式進(jìn)行,對(duì)象轉(zhuǎn)換的速度快,雖然get set 方式代碼對(duì)一些比較麻煩,但是效率要高一些的,推薦使用 MapStruct 方式.,需要的朋友可以參考下
    2021-05-05
  • @RequestParam注解加與不加有什么區(qū)別

    @RequestParam注解加與不加有什么區(qū)別

    這篇文章主要介紹了@RequestParam注解加與不加有什么區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • 用Java實(shí)現(xiàn)全國(guó)天氣預(yù)報(bào)的api接口調(diào)用示例

    用Java實(shí)現(xiàn)全國(guó)天氣預(yù)報(bào)的api接口調(diào)用示例

    查詢天氣預(yù)報(bào)在APP中常用的一個(gè)常用功能,本文實(shí)例講述了java調(diào)用中國(guó)天氣網(wǎng)api獲得天氣預(yù)報(bào)信息的方法。分享給大家供大家參考。
    2016-10-10
  • 在Ubuntu系統(tǒng)下安裝JDK和Tomcat的教程

    在Ubuntu系統(tǒng)下安裝JDK和Tomcat的教程

    這篇文章主要介紹了在Ubuntu系統(tǒng)下安裝JDK和Tomcat的教程,這樣便是在Linux系統(tǒng)下搭建完整的Java和JSP開發(fā)環(huán)境,需要的朋友可以參考下
    2015-08-08
  • MyBatis-plus報(bào)錯(cuò)Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are required的解決方法

    MyBatis-plus報(bào)錯(cuò)Property ‘sqlSessionFactory‘ or 

    這篇文章主要給大家介紹了MyBatis-plus 報(bào)錯(cuò) Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are required的兩種解決方法,如果遇到相同問題的朋友可以參考借鑒一下
    2023-12-12
  • Mybatis中where標(biāo)簽與if標(biāo)簽結(jié)合使用詳細(xì)說明

    Mybatis中where標(biāo)簽與if標(biāo)簽結(jié)合使用詳細(xì)說明

    mybatis中if和where用于動(dòng)態(tài)sql的條件拼接,在查詢語(yǔ)句中如果缺失某個(gè)條件,通過if和where標(biāo)簽可以動(dòng)態(tài)的改變查詢條件,下面這篇文章主要給大家介紹了關(guān)于Mybatis中where標(biāo)簽與if標(biāo)簽結(jié)合使用的詳細(xì)說明,需要的朋友可以參考下
    2023-03-03
  • Spring的注解簡(jiǎn)單介紹

    Spring的注解簡(jiǎn)單介紹

    這篇文章主要介紹了Spring的注解簡(jiǎn)單介紹,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2017-12-12

最新評(píng)論