首頁 > Java > java教程 > SpringBoot異步與事務一起使用的問題怎麼解決

SpringBoot異步與事務一起使用的問題怎麼解決

WBOY
發布: 2023-05-27 14:37:24
轉載
1291 人瀏覽過

最近遇到的一個場景,在一個被@Transactional 註解的方法A中調用了一個被@Async 註解標記的方法B,由於方法B 在執行時方法A 的事務沒有提交,但是方法B在執行過程中取得不到方法A中尚未提交的資料,從而最終倒是方法B執行異常。

@Transactional
public void create(User user){
  // 如果用户已存在,则先删除
  delete(user.id);
  // 创建用户
  int userId = insert(user);
  //  更新用户信息
  update(userId);
}
@Async
public void update(Integer userId){
  Icon icon = getUserIcon(userId);
  // 更新用户图片
  updateUserPohot(userId,icon);
}
登入後複製

像上面的程式碼,我為建立使用者的方法上標記了@Transactional交易註解,然後在其中呼叫了update()更新方法,這個方法上標記了@Async 註解。這樣程式碼雖然看起來沒有什麼問題,但是實際在執行update()方法時,由於是其他執行緒去執行的,就會導致有可能create()方法對應的事務還沒有提交,update() 方法就無法讀取取到新插入的user 記錄,導致更新失敗。

解決方案

透過調整邏輯保證事務在呼叫非同步方法之前被提交

這個問題的原因是由於@Transactional 和@Async 註解一起使用導致的,那麼我們可以從這個方向入手,首先我們可以先確認將create()方法的事務提交後,然後再去執行異步更新方法:

public void create(User user){
  int userId = doCreate(user);
  //  更新用户信息
  update(userId);
}
@Transactional
public void doCreate(User user){
    // 如果用户已存在,则先删除
  delete(user.id);
  // 创建用户
  return insert(user);
}
@Async
public void update(Integer userId){
  Icon icon = getUserIcon(userId);
  // 更新用户图片
  updateUserPohot(userId,icon);
}
登入後複製

異步方法放在事務方法外調用,這樣異步方法就能夠讀取到已經提交的事務資料了。

我們可以使用TransactionTemplate取代@Transactional註解

@Autowired
TransactionTemplate transactionTemplate;
public void create(User user){
  int userId = transactionTemplate.execute(status->{
    // 如果用户已存在,则先删除
    delete(user.id);
    // 创建用户
    return insert(user);
  });
  //  更新用户信息
  update(userId);
}
@Async
public void update(Integer userId){
  Icon icon = getUserIcon(userId);
  // 更新用户图片
  updateUserPohot(userId,icon);
}
登入後複製

透過使用TransactionTemplate來細分事務粒度,確保在呼叫非同步方法之前已經提交了事務。

上面的方案基本上都能解決問題,以下是從網路上找到的,spring 給出的解決方案:

@Transactional
public void create(User user){
  // 如果用户已存在,则先删除
  delete(user.id);
  // 创建用户
  int userId = insert(user);
  TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
    @Override
    public void afterCommit() {
      //  更新用户信息
      update(userId);
    }
  });
}
@Async
public void update(Integer userId){
  Icon icon = getUserIcon(userId);
  // 更新用户图片
  updateUserPohot(userId,icon);
}
登入後複製

透過將非同步方法註冊為交易提交後的操作,這樣Spring可以自動幫我們在交易提交後執行對應的操作。

以上是SpringBoot異步與事務一起使用的問題怎麼解決的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:yisu.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板