spring中@Transactional?注解失效的原因及解決辦法
前言
面試中經(jīng)常會被問到事務(wù)失效的場景有哪些,其實在開發(fā)中,若是不了解事務(wù)失效的場景,當你覺得加了事務(wù),就會回滾,就大錯特錯了,今天就來了解一下吧。
一、@Transactional 屬性介紹
1.事務(wù)的傳播行為:propagation
這就是我們常說的事務(wù)的七種傳播行為,默認值:Propagation.REQUIRED
屬性 | 解釋 |
---|---|
Propagation.REQUIRED | 如果當前存在事務(wù),則加入該事務(wù),如果當前不存在事務(wù),則創(chuàng)建一個新的事務(wù)。 |
Propagation.SUPPORTS | 如果當前存在事務(wù),則加入該事務(wù);如果當前不存在事務(wù),則以非事務(wù)的方式繼續(xù)運行。 |
Propagation.MANDATORY | 如果當前存在事務(wù),則加入該事務(wù);如果當前不存在事務(wù),則拋出異常。 |
Propagation.REQUIRES_NEW | 重新創(chuàng)建一個新的事務(wù),如果當前存在事務(wù),暫停當前的事務(wù)。 |
Propagation.NOT_SUPPORTED | 以非事務(wù)的方式運行,如果當前存在事務(wù),暫停當前的事務(wù)。 |
Propagation.NEVER | 以非事務(wù)的方式運行,如果當前存在事務(wù),則拋出異常。 |
Propagation.NESTED | 嵌套事務(wù)。 |
2.事務(wù)的隔離級別:isolation
這就是我們常說的事務(wù)的隔離級別,默認值:Isolation.DEFAULT
屬性 | 解釋 |
---|---|
Isolation.DEFAULT | 使用底層數(shù)據(jù)庫默認的隔離級別 |
Isolation.READ_UNCOMMITTED | 讀未提交 |
Isolation.READ_COMMITTED | 讀已提交 |
Isolation.REPEATABLE_READ | 可重復(fù)讀 |
Isolation.SERIALIZABLE | 串行化 |
3.事務(wù)的超時時間:timeout
- timeout :事務(wù)的超時時間,默認值為 -1。如果超過該時間限制但事務(wù)還沒有完成,則自動回滾事務(wù)。
4.事務(wù)的回滾類型:rollbackFor
- rollbackFor :用于指定能夠觸發(fā)事務(wù)回滾的異常類型,可以指定多個異常類型。
二、@Transactional 失效場景
1.同一個類中方法調(diào)用,注解失效
場景重現(xiàn):當調(diào)用 saveCabinet 方法時,save 方法中出異常不會回滾,如下代碼
@Service public class CabinetServiceImpl implements CabinetService { @Autowired private CabinetMapper cabinetMapper; @Override public void saveCabinet(Cabinet cabinet) { save(cabinet); } @Transactional(rollbackFor = Exception.class) public void save(Cabinet cabinet) { cabinetMapper.insert(cabinet); int i = 1/0; // 模擬出錯 } }
原因分析:spring 中采用動態(tài)代理來實現(xiàn)事務(wù),當同一個類調(diào)用 save 時,不是代理類在調(diào)用,所以掃描不到事務(wù)注解
解決方案1:將 save 方法提到另一個類中,saveCabinet 調(diào)用另一個類的 save 方法(推薦使用)
// 當前類 @Service public class CabinetServiceImpl implements CabinetService { @Autowired private MethodTest methodTest; @Override public void saveCabinet(Cabinet cabinet) { methodTest.save(cabinet); } } // 另一個類 @Service public class MethodTest { @Autowired private CabinetMapper cabinetMapper; @Transactional(rollbackFor = Exception.class) public void save(Cabinet cabinet) { cabinetMapper.insert(cabinet); int i = 1/0; // 模擬出錯 } }
解決方案2:在 CabinetServiceImpl 中自己注入自己,用自己的代理類調(diào)用 save 方法,即 cabinetServiceImpl.save()
@Service public class CabinetServiceImpl implements CabinetService { @Autowired private CabinetMapper cabinetMapper; @Autowired private CabinetServiceImpl cabinetServiceImpl; @Override public void saveCabinet(Cabinet cabinet) { cabinetServiceImpl.save(cabinet); } @Transactional(rollbackFor = Exception.class) public void save(Cabinet cabinet) { cabinetMapper.insert(cabinet); int i = 1/0; // 模擬出錯 } }
2.異常被 catch “吃了”,注解失效
場景重現(xiàn):當調(diào)用 saveCabinet 方法時,方法體被 try-catch 了,不會回滾,如下代碼
@Service public class CabinetServiceImpl implements CabinetService { @Autowired private CabinetMapper cabinetMapper; @Override @Transactional(rollbackFor = Exception.class) public void saveCabinet(Cabinet cabinet) { try { cabinetMapper.insert(cabinet); int i = 1/0; // 模擬出錯 } catch (Exception e) { e.printStackTrace(); } } }
原因分析:異常直接捕獲沒有向上拋出,而是自己處理了,注解捕獲不到異常,所以失效
解決方案:將 catch 到的異常向上拋出 throw new Exception(e);,異常交給注解處理
@Service public class CabinetServiceImpl implements CabinetService { @Autowired private CabinetMapper cabinetMapper; @Override @Transactional(rollbackFor = Exception.class) public void saveCabinet(Cabinet cabinet) throws Exception { try { cabinetMapper.insert(cabinet); int i = 1/0; // 模擬出錯 } catch (Exception e) { e.printStackTrace(); throw new Exception(e); } } }
3.@Transactional 應(yīng)用在非 public 修飾的方法上
- 場景重現(xiàn):當調(diào)用的方法不是 public 修飾時,不會回滾,事務(wù)失效
- 原因分析:在 spring aop 代理時,事務(wù)攔截器會在目標方法的執(zhí)行前后進行攔截,其中的方法會去獲取 Transactional 注解的一些信息,而其中的方法會去檢查目標方法是否被 public 修飾,不是的話獲取不到注解信息
- 解決方案:將調(diào)用的方法訪問修飾符改為 public
4.@Transactional 注解屬性 rollbackFor 設(shè)置錯誤
場景重現(xiàn):當注解沒有指定 rollbackFor 屬性時,如下若拋出 FileNotFoundException 異常則不會回滾
@Service public class CabinetServiceImpl implements CabinetService { @Autowired private CabinetMapper cabinetMapper; @Override @Transactional public void saveCabinet(Cabinet cabinet) throws IOException { cabinetMapper.insert(cabinet); // 模擬出錯 throw new FileNotFoundException(); } }
原因分析:spring 默認拋出未檢查異常,繼承 RuntimeException 或者 Error 才會回滾,其他異常如 FileNotFoundException 則不會回滾
解決方案:指定 rollbackFor 屬性,一般指定 @Transactional(rollbackFor = Exception.class) 即可,也可以指定自定義異常
@Service public class CabinetServiceImpl implements CabinetService { @Autowired private CabinetMapper cabinetMapper; @Override @Transactional(rollbackFor = Exception.class) public void saveCabinet(Cabinet cabinet) throws IOException { cabinetMapper.insert(cabinet); // 模擬出錯 throw new FileNotFoundException(); } }
5.@Transactional 注解屬性 propagation 設(shè)置錯誤
- 使用了不支持事務(wù)的傳播屬性
6.數(shù)據(jù)庫引擎不支持事務(wù)
- 數(shù)據(jù)庫不支持事務(wù)
總結(jié)
到此這篇關(guān)于spring中@Transactional 注解失效的原因及解決辦法的文章就介紹到這了,更多相關(guān)spring @Transactional 失效內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springmvc實現(xiàn)自定義類型轉(zhuǎn)換器示例
本篇文章主要介紹了springmvc實現(xiàn)自定義類型轉(zhuǎn)換器示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-02-02mybatis Interceptor對UpdateTime自動處理的實現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于使用mybatis Interceptor對UpdateTime自動處理的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起看看吧2018-12-12基于Map的computeIfAbsent的使用場景和使用方式
這篇文章主要介紹了基于Map的computeIfAbsent的使用場景和使用方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09java web開發(fā)之購物車功能實現(xiàn)示例代碼
這篇文章主要介紹了java web開發(fā)之購物車功能實現(xiàn)示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10解析Java內(nèi)存分配和回收策略以及MinorGC、MajorGC、FullGC
本節(jié)將會介紹一下:對象的內(nèi)存分配與回收策略;對象何時進入新生代、老年代;MinorGC、MajorGC、FullGC的定義區(qū)別和觸發(fā)條件;還有通過圖示展示了GC的過程。2021-09-09SpringBoot應(yīng)用部署到外置Tomcat的實現(xiàn)
SpringBoot內(nèi)置tomcat使用很方便,本文主要介紹了SpringBoot應(yīng)用部署到外置Tomcat的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2024-07-07SpringBoot security安全認證登錄的實現(xiàn)方法
這篇文章主要介紹了SpringBoot security安全認證登錄的實現(xiàn)方法,也就是使用默認用戶和密碼登錄的操作方法,本文結(jié)合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2023-02-02Java 使用poi把數(shù)據(jù)庫中數(shù)據(jù)導(dǎo)入Excel的解決方法
本篇文章介紹了,Java 使用poi把數(shù)據(jù)庫中數(shù)據(jù)導(dǎo)入Excel的解決方法。需要的朋友參考下2013-05-05Java實現(xiàn)在Word中嵌入多媒體(視頻、音頻)文件
這篇文章主要介紹了Java如何實現(xiàn)在Word中嵌入多媒體(視頻、音頻)文件,文中的示例代碼講解詳細,對我們學習java有一定的幫助,感興趣的同學可以了解一下2021-12-12