一、一些概念
聲明式的事務管理是基於AOP的,在springboot中可以通過@Transactional注解的方式獲得支持,這種方式的優點是:
1)非侵入式,業務邏輯不受事務管理代碼的污染。
2)方法級別的事務回滾,合理划分方法的粒度可以做到符合各種業務場景的事務管理。
本文使用目前最常用的mybatis框架來配置springboot的事務管理機制。下面進入配置方法介紹。
二、開啟事務 一個注解很簡單
@EnableTransactionManagement //開始事務
三、Service
在設計service層的時候,應該合理的抽象出方法包含的內容。
然后將方法用@Trasactional注解注釋,默認的話在拋出Exception.class異常的時候,就會觸發方法中所有數據庫操作回滾,當然這指的是增、刪、改。
當然,@Transational方法是可以帶參數的,具體的參數解釋如下:
屬性 | 類型 | 描述 |
---|---|---|
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 | 不會導致事務回滾的異常類名字數組 |
代碼:
@Service public class GeoFenceService { @Autowired private MoonlightMapper moonlightMapper; @Transactional(rollbackFor = Exception.class)//可以不加直接使用@Transactional public int addGeoFence(GeoFence geoFence) { String formatTime = TimeFunction.transTimeToFormatPerfect(System.currentTimeMillis()); geoFence.setCreateTime(formatTime); geoFence.setUpdateTime(formatTime); return moonlightMapper.insertOne(geoFence); } @Transactional public int batchGeoFence(List<GeoFence> geoFenceList) { String formatTime = TimeFunction.transTimeToFormatPerfect(System.currentTimeMillis()); for (GeoFence geoFence : geoFenceList) { geoFence.setCreateTime(formatTime); geoFence.setUpdateTime(formatTime); } return moonlightMapper.insertBatch(geoFenceList); } }
四、測試一下
可以做一個簡單的測試,主動拋出異常,測試一下是否真的能保證事務性。
在執行完插入之后,手動拋出一個空指針異常,可以發現數據真的回滾了。
@Service public class GeoFenceService { @Autowired private MoonlightMapper moonlightMapper; @Transactional public int addGeoFence(GeoFence geoFence) { String formatTime = TimeFunction.transTimeToFormatPerfect(System.currentTimeMillis()); geoFence.setCreateTime(formatTime); geoFence.setUpdateTime(formatTime); int count = moonlightMapper.insertOne(geoFence); String a = null; a.indexOf('c'); return count; } }
五、如果項目啟動報錯不要急,因為我也遇到了,下面解決一下
報錯信息:
使用spring-boot做事務管理時,出現異常:The bean 'xxx' could not be injected as a 'xx.xxxx' because it is a JDK dynamic proxy that implements:
搞了半天發現是因為代理的原因;
異常信息:
解決方案:
因為加了@Transaction的類會自動開啟動態代理,java的代理機制主要有JDK動態代理和CGLIB,報上面的錯誤是因為使用了JDK動態代理機制,我嘗試開啟@Transaction設置@EnableTransactionManagement(proxyTargetClass = true),問題解決;特此記錄一下;