springBoot service層事務控制的操作
springBoot使用事物比較簡單,在Application啟動類s上添加@EnableTransactionManagement註解,然後在service層的方法上添加@Transactional註解
@Transactional屬性
屬性 | 類型 | 描述 |
---|---|---|
value | String | 可選的限定描述符,指定使用的事務管理器 |
propagation | enum: Propagation | 可選的事務傳播行為設置 |
isolation | enum: Isolation | 可選的事務隔離級別設置 |
readOnly | boolean | 讀寫或隻讀事務,默認讀寫 |
timeout | int (in seconds granularity) | 事務超時時間設置 |
rollbackFor | Class對象數組,必須繼承自Throwable | 導致事務回滾的異常類數組 |
rollbackForClassName | 類名數組,必須繼承自Throwable | 導致事務回滾的異常類名字數組 |
noRollbackFor | Class對象數組,必須繼承自Throwable | 不會導致事務回滾的異常類數組 |
noRollbackForClassName | 類名數組,必須繼承自Throwable | 不會導致事務回滾的異常類名字數組 |
用法:
@Transactional 可以作用於接口、接口方法、類以及類方法上。當作用於類上時,該類的所有 public 方法將都具有該類型的事務屬性,同時,我們也可以在方法級別使用該標註來覆蓋類級別的定義。
雖然 @Transactional 註解可以作用於接口、接口方法、類以及類方法上,但是 Spring 建議不要在接口或者接口方法上使用該註解,因為這隻有在使用基於接口的代理時它才會生效。
另外, @Transactional 註解應該隻被應用到 public 方法上,這是由 Spring AOP 的本質決定的。
如果你在 protected、private 或者默認可見性的方法上使用 @Transactional 註解,這將被忽略,也不會拋出任何異常。
默認情況下,隻有來自外部的方法調用才會被AOP代理捕獲,也就是,類內部方法調用本類內部的其他方法並不會引起事務行為,即使被調用方法使用@Transactional註解進行修飾。
註解在方法上:
@Autowired private MyBatisDao dao; @Transactional @Override public void insert(Test test) { dao.insert(test); throw new RuntimeException("test");//拋出unchecked異常,觸發事物,回滾 }
@Transactional(noRollbackFor=RuntimeException.class) @Override public void insert(Test test) { dao.insert(test); //拋出unchecked異常,觸發事物,noRollbackFor=RuntimeException.class,不回滾 throw new RuntimeException("test"); }
@Transactional(propagation=Propagation.NOT_SUPPORTED) @Override public void insert(Test test) { //事物傳播行為是PROPAGATION_NOT_SUPPORTED,以非事務方式運行,不會存入數據庫 dao.insert(test); }
註解在類上:當作用於類上時,該類的所有 public 方法將都具有該類型的事務屬性
@Transactional public class MyBatisServiceImpl implements MyBatisService { @Autowired private MyBatisDao dao; @Override public void insert(Test test) { dao.insert(test); //拋出unchecked異常,觸發事物,回滾 throw new RuntimeException("test"); }
註意:有時候在開發時往往出現瞭添加註解後卻無法回滾
原因:默認spring事務隻在發生未被捕獲的 RuntimeException 時才回滾。
spring aop 異常捕獲原理:被攔截的方法需顯式拋出異常,並不能經任何處理,這樣aop代理才能捕獲到方法的異常,才能進行回滾,默認情況下aop隻捕獲 RuntimeException 的異常,但可以通過配置來捕獲特定的異常並回滾
換句話說在service的方法中不使用try catch 或者在catch中最後加上throw new runtimeexcetpion(),這樣程序異常時才能被aop捕獲進而回滾。
解決方案:
1.在service層方法拋出RuntimeException異常(如在Catch中需要拋出自定義的異常則隻需自定義異常繼承RuntimeException即可),並繼續捕獲和處理這個異常。
2.在service層方法的catch語句中增加:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
語句,手動回滾,這樣上層就無需去處理異常。
補充:springboot多個service互相調用的事務處理
今天,想在一個service的方法A中,調用另一個service的方法B,方法A和方法B均存在數據庫插入操作,並且@Transaction註解也都加瞭,但是當B方法中拋出異常時,A中的插入語句還是能夠執行成功。
註解配置如下:
@Transactional(isolation= Isolation.DEFAULT,propagation= Propagation.REQUIRED)
百思不得其解,再查找瞭相關資料後,問題還是出在@Transaction註解的配置上,需要配置異常回滾。
@Transactional(isolation= Isolation.DEFAULT,propagation= Propagation.REQUIRED,rollbackFor = Exception.class)
這樣,當B方法中拋出異常時,A中的操作也會進行回滾,事務就會起到控制作用。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。如有錯誤或未考慮完全的地方,望不吝賜教。
推薦閱讀:
- Java @Transactional指定回滾條件
- Java spring事務及事務不生效的原因詳解
- 解決@Transactional註解事務不回滾不起作用的問題
- 詳細談談Spring事務是如何管理的
- Spring中@Transactional(rollbackFor=Exception.class)屬性用法介紹