一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - 學習spring事務與消息隊列

學習spring事務與消息隊列

2020-06-22 12:38登頂 JAVA教程

這篇文章主要為大家詳細介紹了spring事務與消息隊列,具有一定的參考價值,感興趣的小伙伴們可以參考一下

在開發過程中,遇到一個bug,產生bug的原因是spring事務提交晚于消息隊列的生產消息,導致消息隊列消費消息時獲取到的數據不正確。這篇文章介紹問題的產生和一步步的解決過程。

一.問題的產生:

場景還原:接口中的一個方法,首先修改訂單狀態,然后向消息隊列中生產消息,消息隊列的消費者獲取到消息檢測訂單狀態,發現訂單狀態未更改。

代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Service(orderApi)
public class OrderApiImpl implements OrderApi {
  @Resource MqService mqService;
  @OrderDao orderDao;
   
  public void push(String orderId) {
    // 更新訂單狀態,之前的狀態是1
    updateStatus(orderId, 3);
    // 產生消息
    mqService.produce(orderId);
  }
  public viod updateStatus(String orderId, Integer status) {
    orderDao.updateStatus(orderId, status);
  }
}

問題產生原因:orderApi中的所有方法都有事務,事務類型PROPAGATION_REQUIRED,所以push方法對數據的操作會在push代碼全部執行之后提交,而在事務提交之前消息隊列的消息已經產生所以消息隊列中消費到的訂單從數據庫查詢出的狀態可能還為1。為了讓bug現象更明顯,可以在push方法最后添加:

?
1
2
3
4
5
6
try {
  Thread.sleep(10000);
} catch (InterruptedException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
}

這樣就會發現消費消息時,訂單狀態一定是未修改的。 

二.問題的解決:

解決方案:在更新數據時,新建一個事物,保證更新代碼執行完成后,更新數據庫的事務已被提交。(確保消息產生前數據庫操作已提交)

按照上述方案,我首先想到的是直接修改updateStatus方法的事務類型;我將此方法的事務類型改為PROPAGATION_REQUIRES_NEW(新建事務,如果當前存在事務,把當前事務掛起)。

但是這么做有兩點不合適:

  1.強制修改了updateStaus的事務類型,可能影響其他流程。

  2.未起到作用,updateStaus方法中沒有新建事務。

關于第二點的解釋:spring添加事務是通過BeanNameAutoProxyCreator實現的動態代理,只是給bean對象添加了事務,現在在類內部調用方法,是不會觸發新事物的創建的。

所以在經過以上嘗試后,我創建了一個新的類:

?
1
2
3
4
5
6
7
8
@Service("orderExtApi")
public class OrderExtApiImpl {
  @Resource OrderApi orderApi;
   
  public void updateStatusNewPropagation(String orderId) {
    orderApi.updateStatus(orderId);
  }
}

并為updateStatusNewPropagation方法添加事務PROPAGATION_REQUIRES_NEW

這個類就只是為了給orderApi中的updateStaus方法新起一個事務。

ok,到此為止bug已經解決了。

但是代碼中還是存在問題:對數據庫的操作已經提交,如果生產消息出現異常對業務邏輯來說還是錯誤的。所以需要檢測消息的產生是否完成。

最終orderApi中的代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Service(orderApi)
public class OrderApiImpl implements OrderApi {
  @Resource MqService mqService;
  @Resource OrderDao orderDao;
  @Resource OrderExtApiImpl orderExtApi;
   
  public void push(String orderId) {
    // 更新訂單狀態,之前的狀態是1
    orderExtApi.updateStatusNewPropagation(orderId, 3);
    // 產生消息--produce會檢測是否出現異常 當返回1時表示生產消息成功
    Response response = mqService.produce(orderId);
    if (response.getCode() != 1) {
      log.info("消息隊列生產消息異常:" + response.getErrorMsg())
      // 生產消息異常,重置狀態 等待下次重新執行
      orderExtApi.updateStatusNewPropagation(orderId, 1);
    }
     
  }
  public viod updateStatus(String orderId, Integer status) {
    orderDao.updateStatus(orderId, status);
  }
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产精品亚洲片在线观看麻豆 | 国产精品久久久久久影院 | 国产日韩免费视频 | 98在线视频噜噜噜国产 | 大杳蕉在线影院在线播放 | 我和老丈洗澡同性 | 麻豆网站在线免费观看 | a级影视 | 午夜看片a福利在线观看 | 91次元成年破解版 | 国产亚洲福利精品一区二区 | 91中文字幕yellow字幕网 | 日韩免费一级 | 美国一级大黄大色毛片 | 国产自产自拍 | 倩女还魂在线观看完整版免费 | 日本在线播放视频 | 欧美日韩国产精品va | 国色天香社区在线视频免费观看 | 92在线视频 | www.男人的天堂 | japan在线观看 | 欧美二区三区 | 成年人在线播放视频 | 男同桌扒开女同桌胸罩喝奶 | 国产欧美精品一区二区三区四区 | 高h文恩好大好爽 | 欧美xxxxx九色视频免费观看 | 国产免费又粗又猛又爽视频国产 | 日韩毛片高清在线看 | 第一福利在线视频 | 日本韩国无矿砖码 | 亚洲AV久久久噜噜噜久久 | 扒开腚眼子视频大全 | 国模李丽莎大尺度啪啪 | 久久机热视频 这里只有精品首页 | 午夜福利理论片在线播放 | 久久中文字幕免费高清 | 久久久无码精品无码国产人妻丝瓜 | 日韩亚洲人成在线 | 美女全身体光羞羞漫画 |