@Transactional 事務(wù)失效的場景

一、未指定回滾異常
二逻族、異常被捕獲
三蜻底、方法內(nèi)部直接調(diào)用
四、方法被private或者final修飾
五聘鳞、使用了錯(cuò)誤的事務(wù)傳播機(jī)制
六薄辅、當(dāng)前類沒有被Spring容器托管
七、數(shù)據(jù)庫不支持事務(wù)

一抠璃、未指定回滾異常

@Transactional注解默認(rèn)的回滾異常類型是運(yùn)行時(shí)異常(RuntimeException)站楚,如果我們自定義了一個(gè)異常直接繼承了Exception,例如:

public class CustomException extends Exception

如果@Transactional未指定異常類型搏嗡,當(dāng)程序中拋出CustomException異常則不會(huì)回滾,例如:

@Transactional
public void save(BaseDTO dto) throws CustomException{
    try {
        BasePO po = new BasePO();
        BeanUtil.copyProperties(dto, po,true);
        int insert = baseTestMapper.insert(po);
        String[] a = new String[]{"1","2"};
        String s = a[3];
    }catch (Exception e){
        throw new CustomException(CustomErrorEnum.FAIL);
    }
}

結(jié)果如下:

2024-08-26 10:48:03.306  INFO 4771 --- [nio-8081-exec-6]     o.a.d.remoting.transport.AbstractClient  :  [DUBBO] Start NettyClient /10.1.186.51 connect to the server /10.1.186.51:20880, dubbo version: 2.7.15, current host: 10.1.186.51
2024-08-26 10:48:03.936 ERROR 4771 --- [nio-8081-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is CustomException(code=50000, msg=請求失敗!, data=null)] with root cause

exception.CustomException: 請求失敗!
at com.base.dubboservice.iservice.IBaseServiceImpl.save(IBaseServiceImpl.java:49) ~[na:na]
at com.base.dubboservice.iservice.IBaseServiceImpl$$FastClassBySpringCGLIB$$652c9b76.invoke(<generated>) ~[na:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.25.jar:5.3.25]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.25.jar:5.3.25]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.25.jar:5.3.25]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.25.jar:5.3.25]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[na:na]

雖然程序當(dāng)中拋出了異常采盒,但是數(shù)據(jù)庫還是成功入庫了旧乞。

此時(shí)我們需要在@Transactional指定回滾異常的類型,遇到指定類型異常就要回滾:@Transactional(rollbackFor = CustomException.class)

@Override
@Transactional(rollbackFor = CustomException.class)
public void save(BaseDTO dto) throws CustomException{
    try {
        BasePO po = new BasePO();
        BeanUtil.copyProperties(dto, po,true);
        int insert = baseTestMapper.insert(po);
        String[] a = new String[]{"1","2"};
        String s = a[3];
    }catch (Exception e){
        throw new CustomException(CustomErrorEnum.FAIL);
    }
}

二磅氨、異常被捕獲

異常被try-catch捕獲時(shí)尺栖,事務(wù)也會(huì)失效:

@Override
@Transactional
public void save(BaseDTO dto) throws CustomException{
    try {
        BasePO po = new BasePO();
        BeanUtil.copyProperties(dto, po,true);
        int insert = baseTestMapper.insert(po);
        String[] a = new String[]{"1","2"};
        String s = a[3];
    }catch (Exception e){
    }
}

所以我們需要主動(dòng)將此異常拋出: throws CustomException。

@Override
@Transactional(rollbackFor = CustomException.class)
public void save(BaseDTO dto) throws CustomException{
    try {
        BasePO po = new BasePO();
        BeanUtil.copyProperties(dto, po,true);
        int insert = baseTestMapper.insert(po);
        String[] a = new String[]{"1","2"};
        String s = a[3];
    }catch (Exception e){
        throw new CustomException(CustomErrorEnum.FAIL);
    }
}

或者我們也可以修改catch包裹的代碼烦租,以此來達(dá)到回滾的目的延赌。

@Override
@Transactional
public void save(BaseDTO dto){
    try {
        BasePO po = new BasePO();
        BeanUtil.copyProperties(dto, po,true);
        int insert = baseTestMapper.insert(po);
        String[] a = new String[]{"1","2"};
        String s = a[3];
    }catch (Exception e){
        e.printStackTrace();
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}

三、方法內(nèi)部直接調(diào)用

在Spring的Aop代理下叉橱,只有目標(biāo)方法在外部進(jìn)行調(diào)用挫以,目標(biāo)方法才會(huì)由Spring生成的代理對象來進(jìn)行管理,如果是其他不包含@Transactional注解的方法中調(diào)用包含@Transactional注解的方法時(shí)候赏迟,有@Transactional注解的方法的事務(wù)會(huì)被忽略屡贺,則不會(huì)發(fā)生回滾。

@Override
public void save(BaseDTO dto){
    saveTransactional(dto);
}

@Transactional
public void saveTransactional(BaseDTO dto){
    try {
        BasePO po = new BasePO();
        BeanUtil.copyProperties(dto, po,true);
        int insert = baseTestMapper.insert(po);
        String[] a = new String[]{"1","2"};
        String s = a[3];
    }catch (Exception e){
        e.printStackTrace();
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}

修改方式,把當(dāng)前類自己注入一下調(diào)用即可甩栈。

@Autowired
IBaseServiceImpl iBaseService;


@Override
public void save(BaseDTO dto){
    iBaseService.saveTransactional(dto);
}

@Transactional
public void saveTransactional(BaseDTO dto){
    try {
        BasePO po = new BasePO();
        BeanUtil.copyProperties(dto, po,true);
        int insert = baseTestMapper.insert(po);
        String[] a = new String[]{"1","2"};
        String s = a[3];
    }catch (Exception e){
        e.printStackTrace();
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}

Spring Boot 2.6 后泻仙,把當(dāng)前類自己注入 會(huì)報(bào)循環(huán)引用問題 ×棵唬可添加配置打破循環(huán) 玉转。

spring:
  main:
    allow-circular-references: true

四、方法被private修飾

此種情況下殴蹄,事務(wù)也是會(huì)失效的究抓。

@Transactional
private void saveTransactional(BaseDTO dto){
    asePO po = new BasePO();
    BeanUtil.copyProperties(dto, po,true);
    int insert = baseTestMapper.insert(po);
    dto.setTranName("999");
    String[] a = new String[]{"1","2"};
    String s = a[3];
}

五、使用了錯(cuò)誤的事務(wù)傳播機(jī)制
六袭灯、當(dāng)前類沒有被Spring容器托管
七刺下、數(shù)據(jù)庫不支持事務(wù)


文章持續(xù)更新中、希望對各位有所幫助稽荧、有問題可留言 大家共同學(xué)習(xí).

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末橘茉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子姨丈,更是在濱河造成了極大的恐慌畅卓,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蟋恬,死亡現(xiàn)場離奇詭異翁潘,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)歼争,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門拜马,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人沐绒,你說我怎么就攤上這事一膨。” “怎么了洒沦?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長价淌。 經(jīng)常有香客問我申眼,道長,這世上最難降的妖魔是什么蝉衣? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任括尸,我火速辦了婚禮,結(jié)果婚禮上病毡,老公的妹妹穿的比我還像新娘濒翻。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布有送。 她就那樣靜靜地躺著淌喻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪雀摘。 梳的紋絲不亂的頭發(fā)上裸删,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音阵赠,去河邊找鬼涯塔。 笑死,一個(gè)胖子當(dāng)著我的面吹牛清蚀,可吹牛的內(nèi)容都是我干的匕荸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼枷邪,長吁一口氣:“原來是場噩夢啊……” “哼榛搔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起齿风,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤药薯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后救斑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體童本,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年脸候,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了穷娱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡运沦,死狀恐怖泵额,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情携添,我是刑警寧澤嫁盲,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站烈掠,受9級(jí)特大地震影響羞秤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜左敌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一瘾蛋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧矫限,春花似錦哺哼、人聲如沸佩抹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽棍苹。三九已至,卻和暖如春甲葬,著一層夾襖步出監(jiān)牢的瞬間廊勃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國打工经窖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坡垫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓画侣,卻偏偏與公主長得像冰悠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子配乱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容