欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

spring中@Transactional?注解失效的原因及解決辦法

 更新時間:2024年06月05日 09:19:02   作者:睡個好覺  
面試中經(jīng)常會被問到事務(wù)失效的場景有哪些,本文主要介紹了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)文章

最新評論