Spring事務什么時候會失效?


面試官:Spring事務什么時候會失效?

應聘者:

  • 訪問權限問題

  • 方法用final修飾

  • 未被Spring管理

  • 錯誤的傳播特性

  • 自己吞了異常

  • 手動拋了別的異常

  • 自定義了回滾異常

  • 方法內部調用

 

1、訪問權限問題

Java的訪問權限主要有三種:private、protected、public,它們的權限從左到右,依次變大。但如果我們在開發過程中,把有某些事務方法,定義了錯誤的訪問權限,就會導致事務功能出問題,例如:

1 @Service 2 public class OrderService { 3  @Transactional 4     private void add(OrderVO orderVO) { 5  saveData(orderVO); 6  } 7 }

從上面可以看到add方法的訪問權限是private修飾的,這樣會導致事務失效,spring要求被代理方法必須是public的,事務會失效。

 

2、方法final修飾的

當某個方法被final修飾時,子類是無法繼承和重載的,事務是基於動態代理去實現的,如果某個方法用final修飾了,那么在它的代理類中,就無法重寫該方法,而添加事務功能。

1 @Service 2 public class OrderService { 3  @Transactional 4     public final void add(OrderVO orderVO) { 5  saveData(orderVO); 6  } 7 }

 

3、未被Spring管理

使用spring事務的前提是:對象要被spring管理,需要創建bean實例。如果,你開發了一個Service類,但忘了加@Service注解,比如:

1 //@Service
2 public class OrderService { 3  @Transactional 4     public final void add(OrderVO orderVO) { 5  saveData(orderVO); 6  } 7 }

又或者XML里面配置納入Spring管理的包文件路徑配置錯誤等。

 

4、錯誤的傳播特性

我們在使用@Transactional注解時,是可以指定propagation參數的。該參數的作用是指定事務的傳播特性,spring目前支持7種傳播特性:

  • REQUIRED:如果當前上下文中存在事務,那么加入該事務,如果不存在事務,創建一個事務,這是默認的傳播屬性值;

  • SUPPORTS:如果當前上下文存在事務,則支持事務加入事務,如果不存在事務,則使用非事務的方式執行;

  • MANDATORY:如果當前上下文中存在事務,否則拋出異常;

  • REQUIRES_NEW:每次都會新建一個事務,並且同時將上下文中的事務掛起,執行當前新建事務完成以后,上下文事務恢復再執行;

  • NOT_SUPPORTED:如果當前上下文中存在事務,則掛起當前事務,然后新的方法在沒有事務的環境中執行;

  • NEVER:如果當前上下文中存在事務,則拋出異常,否則在無事務環境上執行代碼;

  • NESTED:如果當前上下文中存在事務,則嵌套事務執行,如果不存在事務,則新建事務;

如果我們在手動設置propagation參數的時候,把傳播特性設置錯了,比如:

1 @Service 2 public class OrderService { 3     @Transactional(propagation = Propagation.NEVER) 4     public void add(OrderVO orderVO) { 5  saveData(orderVO); 6     }

 

5、自己吞了異常

事務不會回滾,最常見的問題是:開發者在代碼中手動try...catch了異常。比如:

 1 @Service  2 public class OrderService {  3  @Transactional  4     public void add(OrderVO orderVO) {  5         try{  6  saveData(orderVO);  7         } catch(Exception e) {  8  log.error(e);  9  } 10  } 11 }

這種情況下spring事務當然不會回滾,因為開發者自己捕獲了異常,又沒有手動拋出,換句話說就是把異常吞掉了。

如果想要spring事務能夠正常回滾,必須拋出它能夠處理的異常。如果沒有拋異常,則spring認為程序是正常的。

 

6、手動拋了別的異常

即使開發者沒有手動捕獲異常,但如果拋的異常不正確,spring事務也不會回滾。

 1 @Service  2 public class OrderService {  3  @Transactional  4     public void add(OrderVO orderVO) {  5         try{  6  saveData(orderVO);  7         } catch(Exception e) {  8  log.error(e);  9             throw new Exception(e); 10  } 11  } 12 }

上面的這種情況,開發人員自己捕獲了異常,又手動拋出了異常:Exception,事務同樣不會回滾。因為spring事務,默認情況下只會回滾RuntimeException(運行時異常)和Error(錯誤),對於普通的Exception(非運行時異常),它不會回滾。

 

7、自定義了回滾異常

@Transactional注解聲明事務時,有時我們想自定義回滾的異常,spring也是支持的。可以通過設置rollbackFor參數,來完成這個功能。

1 @Service 2 public class OrderService { 3     @Transactional(rollbackFor = BusinessException.class) 4     public void add(OrderVO orderVO) { 5  saveData(orderVO); 6  } 7 }

如果在執行上面這段代碼,保存和更新數據時,程序報錯了,拋了SqlException、NullPointerException等異常。而BusinessException是我們自定義的異常,報錯的異常不屬於BusinessException,所以事務也不會回滾。

 

8、方法內部調用

有時候我們需要在某個Service類的某個方法中,調用另外一個事務方法,比如:

 1 @Service  2 public class OrderService {  3  @Transactional  4     public void add(OrderVO orderVO) {  5  saveData(orderVO);  6  }  7 
 8  @Transactional  9     public void saveData(OrderVO orderVO) { 10  doSameThing(); 11  } 12 }

我們看到在事務方法add中,直接調用事務方法saveData。saveData方法擁有事務的能力是因為Spring Aop生成代理了對象,但是這種方法直接調用了this對象的方法,所以saveData方法不會生成事務。

由此可見,在同一個類中的方法直接內部調用,會導致事務失效。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM