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

SpringBoot事務異步調用引發(fā)的bug解決

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

前言

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

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

因為需要同時要創(chuàng)建導出任務和導出任務歷史兩條記錄,所以代碼中需要通常要添加事務

@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層只需要調用service的方法即可

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

我們使用了xxl-job去觸發(fā)任務是一個異步調用的過程,當xxl-job回調執(zhí)行器去執(zhí)行時可能需要根據(jù)job_id獲取到導出任務的配置,通過查詢db獲取任務詳情,比如導出地址了,導出規(guī)范等等。
看似非常和諧的場面,實際執(zhí)行起來則會出現(xiàn)任務不存在的問題。問題的根源其實也很好理解,就是因為在異步方法里做了同步的事就會出現(xiàn)這種問題,當?shù)谝徊經]有執(zhí)行完,第三步的回調方法已經到執(zhí)行器了,也就是說一個任務還沒存到數(shù)據(jù)庫,執(zhí)行這個任務時去數(shù)據(jù)庫查該任務的明細肯定會報任務不存在異常了。
那么如何解決呢。

代碼拆分

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

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

如果秉持著代碼和人有一個能跑就行的原則,此時已經結束戰(zhàn)斗了,對于秉持著該原則且有點代碼潔癖同學頂多也就是把觸發(fā)任務的動作封裝到一個觸發(fā)service里調用。

TransactionSynchronizationManager事務回調

當然還是有很多同學對待技術是追求極致精神的,那么有沒有優(yōu)雅的方式去解決這個問題,那就要看springboot的事務回調能力了。

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

直接上代碼舉例子

@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
? ? ? ? ? ? }
? ? ? ? });
? ? }
}

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

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

TransactionalEventListener,自 Spring 4.2 以來,可以使用基于注釋的配置為提交后事件(或更一般的事務同步事件,例如回滾)定義偵聽器。本質上是基于核心 spring中的事件處理。使用這種方法可以避免對 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) {
? ? ? ? ?// 處理失敗,拋出異常,事務回滾
? ? ? ? ?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) {
? ? ? ? ?// 處理失敗,不影響事務
? ? ? ? ?e.printStackTrace();
? ? ? }
? ?}
}

定義事件

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

@TransactionalEventListener注解要和@Transactional注解配合使用,確保在事務完成后才會觸發(fā)回調方法。@TransactionalEventListener注解也可以指定回調方法的觸發(fā)時機,可以選擇在事務提交后觸發(fā)(默認)或在事務回滾后觸發(fā)。

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

相關文章

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

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

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

    Java命名規(guī)則詳細總結

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

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

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

    深入理解Java對象復制

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

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

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

    用Java實現(xiàn)全國天氣預報的api接口調用示例

    查詢天氣預報在APP中常用的一個常用功能,本文實例講述了java調用中國天氣網(wǎng)api獲得天氣預報信息的方法。分享給大家供大家參考。
    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報錯Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are required的解決方法

    MyBatis-plus報錯Property ‘sqlSessionFactory‘ or 

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

    Mybatis中where標簽與if標簽結合使用詳細說明

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

    Spring的注解簡單介紹

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

最新評論