溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

SpringBoot異步與事務(wù)一起使用的問(wèn)題怎么解決

發(fā)布時(shí)間:2023-05-05 14:27:59 來(lái)源:億速云 閱讀:93 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要講解了“SpringBoot異步與事務(wù)一起使用的問(wèn)題怎么解決”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“SpringBoot異步與事務(wù)一起使用的問(wèn)題怎么解決”吧!

最近遇到的一個(gè)場(chǎng)景,在一個(gè)被 @Transactional 注解的方法A中中調(diào)用了一個(gè)被 @Async 注解標(biāo)記的方法B,由于方法B 在執(zhí)行時(shí)方法A 的事務(wù)沒(méi)有提交,但是方法B在執(zhí)行過(guò)程中獲取不到方法A中尚未提交的數(shù)據(jù),從而最終倒是方法B執(zhí)行異常。

@Transactional
public void create(User user){
  // 如果用戶已存在,則先刪除
  delete(user.id);
  // 創(chuàng)建用戶
  int userId = insert(user);
  //  更新用戶信息
  update(userId);
}
@Async
public void update(Integer userId){
  Icon icon = getUserIcon(userId);
  // 更新用戶圖片
  updateUserPohot(userId,icon);
}

像上面的代碼,我為創(chuàng)建用戶的方法上標(biāo)記了@Transactional事務(wù)注解,然后在其中調(diào)用了update()更新方法,這個(gè)方法上標(biāo)記了@Async 注解。這樣代碼雖然看起來(lái)沒(méi)有什么問(wèn)題,但是實(shí)際在執(zhí)行update()方法時(shí),由于是其他線程去執(zhí)行的,就會(huì)導(dǎo)致有可能 create()方法對(duì)應(yīng)的事務(wù)還沒(méi)有提交,update() 方法就無(wú)法讀取到新插入的 user 記錄,從而導(dǎo)致更新失敗。

解決方案

通過(guò)調(diào)整邏輯保證事務(wù)在調(diào)用異步方法前被提交

這個(gè)問(wèn)題的原因是由于 @Transactional 和 @Async 注解一起使用導(dǎo)致的,那么我們可以從這個(gè)方向入手,首先我們可以先確認(rèn)將create()方法的事務(wù)提交后,然后再去執(zhí)行異步更新方法:

public void create(User user){
  int userId = doCreate(user);
  //  更新用戶信息
  update(userId);
}
@Transactional
public void doCreate(User user){
    // 如果用戶已存在,則先刪除
  delete(user.id);
  // 創(chuàng)建用戶
  return insert(user);
}
@Async
public void update(Integer userId){
  Icon icon = getUserIcon(userId);
  // 更新用戶圖片
  updateUserPohot(userId,icon);
}

異步方法放在事務(wù)方法外調(diào)用,這樣異步方法就能夠讀取到已經(jīng)提交的事務(wù)數(shù)據(jù)了。

或者我們還可以使用TransactionTemplate來(lái)代替 @Transactional 注解:

@Autowired
TransactionTemplate transactionTemplate;
public void create(User user){
  int userId = transactionTemplate.execute(status->{
    // 如果用戶已存在,則先刪除
    delete(user.id);
    // 創(chuàng)建用戶
    return insert(user);
  });
  //  更新用戶信息
  update(userId);
}
@Async
public void update(Integer userId){
  Icon icon = getUserIcon(userId);
  // 更新用戶圖片
  updateUserPohot(userId,icon);
}

通過(guò) TransactionTemplate細(xì)化了事務(wù)粒度,可以保證在調(diào)用異步方法前事務(wù)已經(jīng)被提交。

上面的方案基本都能 解決問(wèn)題,下面是從網(wǎng)上找到的,spring 給出的解決方案:

@Transactional
public void create(User user){
  // 如果用戶已存在,則先刪除
  delete(user.id);
  // 創(chuàng)建用戶
  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);
}

通過(guò)將異步方法注冊(cè)為事務(wù)提交后的操作,這樣Spring可以自動(dòng)幫我們?cè)谑聞?wù)提交后執(zhí)行對(duì)應(yīng)的操作。

感謝各位的閱讀,以上就是“SpringBoot異步與事務(wù)一起使用的問(wèn)題怎么解決”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)SpringBoot異步與事務(wù)一起使用的問(wèn)題怎么解決這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI