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

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

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 完美解決Spring聲明式事務不回滾的問題

完美解決Spring聲明式事務不回滾的問題

2020-11-04 16:46Java教程網 Java教程

下面小編就為大家帶來一篇完美解決Spring聲明式事務不回滾的問題。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

疑問,確實像往常一樣在service上添加了注解 @Transactional,為什么查詢數據庫時還是發現有數據不一致的情況,想想肯定是事務沒起作用,出現異常的時候數據沒有回滾。于是就對相關代碼進行了一番測試,結果發現一下踩進了兩個坑,確實是事務未回滾導致的數據不一致。

下面總結一下經驗教訓:

Spring事務的管理操作方法

編程式的事務管理

實際應用中很少使用

通過使用TransactionTemplate 手動管理事務

聲明式的事務管理

開發中推薦使用(代碼侵入最少)

Spring的聲明式事務是通過AOP實現的

主要掌握聲明式的事務管理。

spring事務不回滾的兩個原因

總結一下導致事務不回滾的兩個原因,一是Service類內部方法調用,二是try...catch異常。

1. Service類內部方法調用

大概就是 Service 中有一個方法 A,會內部調用方法 B, 方法 A 沒有事務管理,方法 B 采用了聲明式事務,通過在方法上聲明 Transactional 的注解來做事務管理。示例代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Service
public class RabbitServiceImpl implements RabbitService {
 
  @Autowired
  private RabbitDao rabbitDao;
  @Autowired
  private TortoiseDao tortoiseDao;
 
  @Override
  public Rabbit methodA(String name){
    return methodB(name);
  }
 
  @Transactional(propagation = Propagation.REQUIRED)
  public boolean methodB(String name){
    rabbitDao.insertRabbit(name);
    tortoiseDao.insertTortoise(name);
    return true;
  }
 
}

單元測試代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class RabbitServiceImplTest {
 
  @Autowired
  private RabbitService rabbitService;
 
  // 事務未開啟
  @Test
  public void testA(){
    rabbitService.methodA("rabbit");
  }
 
  // 事務開啟
  @Test
  public void testB(){
    rabbitService.methodB("rabbit");
  }
}

從上一節中可以看到,聲明式事務是通通過AOP動態代理實現的,這樣會產生一個代理類來做事務管理,而目標類(service)本身是不能感知代理類的存在的。

對于加了@Transactional注解的方法來說,在調用代理類的方法時,會先通過攔截器TransactionInterceptor開啟事務,然后在調用目標類的方法,最后在調用結束后,TransactionInterceptor 會提交或回滾事務,大致流程如下圖:

完美解決Spring聲明式事務不回滾的問題

總結,在方法 A 中調用方法 B,實際上是通過“this”的引用,也就是直接調用了目標類的方法,而非通過 Spring 上下文獲得的代理類,所以事務是不會開啟的。

2. try...catch異常

在一段業務邏輯中對數據庫異常進行了處理,使用了try...catch子句捕獲異常并throw了一個自定義異常,這種情況導致了事務未回滾,示例代碼如下:

?
1
2
3
4
5
6
7
8
9
10
@Transactional(propagation = Propagation.REQUIRED)
public boolean methodB(String name) throws BizException {
  try {
    rabbitDao.insertRabbit(name);
    tortoiseDao.insertTortoise(name);
  } catch (Exception e) {
    throw new BizException(ReturnCode.EXCEPTION.code, ReturnCode.EXCEPTION.msg);
  }
  return true;
}

BizException的定義如下:

?
1
2
3
public class BizException extends Exception {
  // 自定義異常
}

上面代碼中的聲明式事務在出現異常的時候,事務是不會回滾的。在代碼中我雖然捕獲了異常,但是同時我也拋出了異常,為什么事務未回滾呢?猜測是異常類型不對,于是開始查詢原因,翻看了Spring的官方文檔,找到了答案。下面是翻譯自Spring官網。

17.5.3 聲明式事務的回滾

上一節中介紹了如何設置開啟Spring事務,一般在你的應用的Service層代碼中設置,這一節將介紹在簡單流行的聲明式事務中如何控制事務回滾。

在Spring FrameWork 的事務框架中推薦的事務回滾方法是,在當前執行的事務上下文中拋出一個異常。如果異常未被處理,當拋出異常調用堆棧的時候,Spring FrameWork 的事務框架代碼將捕獲任何未處理的異常,然后并決定是否將此事務標記為回滾。

在默認配置中,Spring FrameWork 的事務框架代碼只會將出現runtime, unchecked 異常的事務標記為回滾;也就是說事務中拋出的異常時RuntimeException或者是其子類,這樣事務才會回滾(默認情況下Error也會導致事務回滾)。在默認配置的情況下,所有的 checked 異常都不會引起事務回滾。

注:Unchecked Exception包括Error與RuntimeException. RuntimeException的所有子類也都屬于此類。另一類就是checked Exception。

你可以精確的配置異常類型,指定此異常類事務回滾,包括 checked 異常。下面的xml代碼片段展示了如何配置checked異常引起事務回滾,應用自定義異常類型:

?
1
2
3
4
5
6
<tx:advice id="txAdvice" transaction-manager="txManager">
 <tx:attributes>
 <tx:method name="get*" read-only="true" rollback-for="Exception"/>
 <tx:method name="*"/>
 </tx:attributes>
</tx:advice>

與其有同等作用的注解形式如下:

?
1
2
3
@Transactional(rollbackForClassName={"Exception"})
或者
@Transactional(rollbackFor={Exception.class})

在你遇到異常不想回滾事務的時候,同樣的你也可指定不回滾的規則,下面的一個例子告訴你,即使遇到未處理的 InstrumentNotFoundException 異常時,Spring FrameWork 的事務框架同樣會提交事務,而不回滾。

?
1
2
3
4
5
6
<tx:advice id="txAdvice">
 <tx:attributes>
 <tx:method name="updateStock" no-rollback-for="InstrumentNotFoundException"/>
 <tx:method name="*"/>
 </tx:attributes>
</tx:advice>

與其有同樣作用的注解形式如下:   

?
1
2
3
@Transactional(noRollbackForClassName={"InstrumentNotFoundException"})
或者
@Transactional(noRollbackFor={InstrumentNotFoundException.class})

還有更靈活的回滾規則配置方法,同時指定什么異常回滾,什么異常不回滾。當Spring FrameWork 的事務框架捕獲到一個異常的時候,會去匹配配置的回滾規則來決定是否標記回滾事務,使用匹配度最強的規則結果。因此,下面的配置例子表達的意思是,除了異常 InstrumentNotFoundException 之外的任何異常都會導致事務回滾。

?
1
2
3
4
5
<tx:advice id="txAdvice">
 <tx:attributes>
 <tx:method name="*" rollback-for="Throwable" no-rollback-for="InstrumentNotFoundException"/>
 </tx:attributes>
</tx:advice>

你也可以通過編程式的方式回滾一個事務,盡管方法非常簡單,但是也有非常強的代碼侵入性,使你的業務代碼和Spring FrameWork 的事務框架代碼緊密的綁定在一起,示例代碼如下:

?
1
2
3
4
5
6
7
8
public void resolvePosition() {
 try {
   // some business logic...
 } catch (NoProductInStockException ex) {
   // trigger rollback programmatically
   TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
 }
}

如果可能的話,強烈推薦您使用聲明式事務方式回滾事務,對于編程式事務,如果你強烈需要它,也是可以使用的,but its usage flies in the face of achieving a clean POJO-based architecture.(沒懂...)

看完官方文檔這節內容找到了問題的答案,原來是因為我們自定義的異常不是 RuntimeException。我的解決辦法是,在注解@Transactional中添加 rollbackFor={BizException.class}。可能你會問我為什么不將自定義異常修改為繼承RuntimeException,因為我需要BizException是一個checked 異常。

以上這篇完美解決Spring聲明式事務不回滾的問題就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持服務器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 91噜噜噜噜色 | 亚洲激情成人 | 精品区卡一卡2卡三免费 | 精品视频 久久久 | 日韩经典在线观看 | 久久视频这里只精品99热在线观看 | 国产宅男| 射逼视频 | a毛片免费全部在线播放毛 a级在线看 | 亚洲 欧美 国产 综合久久 | 俄罗斯一级毛片免费播放 | 性做久久久久久久 | 花核调教 | 日本人妖在线 | 98色花堂永久地址国产精品 | 四虎1515hh.com| 视频一区二区国产无限在线观看 | 免费片在线观看高清 | 边打电话边操 | 日韩欧美一级大片 | 無码一区中文字幕少妇熟女网站 | 人人最怕九月羊 | 婷婷综合在线 | 亚洲AV精品无码喷水直播间 | 亚洲伦理一区 | а天堂中文最新版在线官网视频 | 青青成人福利国产在线视频 | 国产免费成人在线视频 | 故意短裙公车被强好爽在线播放 | 欧美一区二区三区四区视频 | 欧美日韩人成在线观看 | 韩国三级视频网站 | 欧美日韩亚洲区久久综合 | 国产高清在线不卡 | 久久精品国产色蜜蜜麻豆国语版 | 亚洲欧美日韩综合在线播放 | 男男羞羞视频网站国产 | 91国产在线第7页 | 亚洲日本va中文字幕 | 8插8插| 天天快乐高清在线观看 |