javascript
SpringBoot - 优雅的处理【长事务】
文章目錄
- Pre
- What
- How
- 方法一 編程式事務
- 使用@Transactional 又能避免產生長事務
- 方法一
- 方法二
Pre
SpringBoot - 實踐阿里巴巴【Manager 層_通用業(yè)務處理層】
在Spring體系中,在方法上加上注解@Transactional,Spring自動幫我們進行事務的開啟、提交、回滾操作,真的是太方便了,以至于不分青紅皂白,啥都搞上…
What
運行時間比較長,長時間未提交的事務,都可以稱之為長事務
長事務引發(fā)的常見危害有:
- 數據庫連接池被占滿,應用無法獲取連接資源
- 容易引發(fā)數據庫死鎖
- 數據庫回滾時間長
- 在主從架構中會導致主從延時變大 等等
How
原則: 對事務方法進行拆分,盡量讓事務變小,變快,減小事務的顆粒度
我們知道@Transactional注解進行事務管理的操作叫聲明式事務, 使用聲明式事務的優(yōu)點 很明顯,簡單,僅需要關注業(yè)務, Spring框架自動幫我們進行事務的開啟、提交以及回滾等操作。
聲明式事務有一個最大的缺點,就是事務的顆粒度是整個方法,無法進行精細化控制。
那 與聲明式事務對應的就是編程式事務 是不是可以解決 顆粒度的問題呢?
方法一 編程式事務
基于底層的API,開發(fā)者在代碼中手動的管理事務的開啟、提交、回滾等操作。
在spring項目中我們可以使用TransactionTemplate類的對象,手動控制事務。
@Autowired private TransactionTemplate transactionTemplate; ... public void save(ArtisanDto artisanDto) { transactionTemplate.execute(transactionStatus -> {artisanDao.save(artisanDto);//....// .....return Boolean.TRUE; }); }使用編程式事務最大的好處就是可以精細化控制事務范圍, 所以避免長事務最簡單的方法就是不要使用聲明式事務@Transactional,而是使用編程式事務手動控制事務范圍。
使用@Transactional 又能避免產生長事務
那既想使用@Transactional 又想避免產生長事務呢?
那就需要對方法進行拆分,將不需要事務管理的邏輯與事務操作分開.
@Service public class ArtisanService{public void create(ArtisanDto dto){queryData();biz();save(dto);}//事務操作@Transactional(rollbackFor = Throwable.class)public void save(ArtisanDto dto){artisanDao.insert(dto);} }queryData()與biz()不需要事務,我們將其與事務方法save()拆開.
這種拆分會命中使用@Transactional注解時事務不生效的經典場景. @Transactional注解的聲明式事務是通過spring aop起作用的,而spring aop需要生成代理對象,直接在同一個類中方法調用使用的還是原始對象,事務不生效。
其他幾個常見的事務不生效的場景為:
- @Transactional 應用在非 public 修飾的方法上
- @Transactional 注解屬性 propagation 設置錯誤
- @Transactional 注解屬性 rollbackFor 設置錯誤
- 同一個類中方法調用,導致@Transactional失效
- 異常被catch捕獲導致@Transactional失效
每日一博 - 常見的Spring事務失效&事務不回滾案例集錦
所以正確的拆分方法應該是下面兩種
方法一
可以將方法放入另一個類,如新增 manager層,通過spring注入,這樣符合了在對象之間調用的條件。
@Service public class ArtisanService{@Autowiredprivate ArtisanManager artisanManager;public void create(ArtisanDto dto){queryData();biz();artisanManager.save(dto);} } @Service public class ArtisanManager{@Autowiredprivate ArtisanDao artisanDao;@Transactional(rollbackFor = Throwable.class)public void save(ArtisanCreateDTO dto){artisanDao.saveData(dto);} }參考 SpringBoot - 實踐阿里巴巴【Manager 層_通用業(yè)務處理層】
方法二
啟動類添加@EnableAspectJAutoProxy(exposeProxy = true),方法內使用AopContext.currentProxy()獲得代理類,使用事務。
@EnableAspectJAutoProxy(exposeProxy = true) @SpringBootApplication public class SpringBootApplication {} public void createArtisan(ArtisanCreateDTO dto){ArtisanService artisanService = (ArtisanService)AopContext.currentProxy();artisanService.saveData(dto); }總結
以上是生活随笔為你收集整理的SpringBoot - 优雅的处理【长事务】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringBoot - 实践阿里巴巴【
- 下一篇: SpringBoot - 子模块下spr