溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Spring的事務(wù)隔離級別與傳播性是什么意思

發(fā)布時間:2021-06-26 14:04:50 來源:億速云 閱讀:144 作者:chen 欄目:大數(shù)據(jù)

這篇文章主要介紹“Spring的事務(wù)隔離級別與傳播性是什么意思”,在日常操作中,相信很多人在Spring的事務(wù)隔離級別與傳播性是什么意思問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Spring的事務(wù)隔離級別與傳播性是什么意思”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

這篇文章以一個問題開始,如果你知道答案的話就可以跳過不看啦@(o???)@

Q:在一個批量任務(wù)執(zhí)行的過程中,調(diào)用多個子任務(wù)時,如果有一些子任務(wù)發(fā)生異常,只是回滾那些出現(xiàn)異常的任務(wù),而不是整個批量任務(wù),請問在Spring中事務(wù)需要如何配置才能實現(xiàn)這一功能呢?

隔離級別

隔離性(Isolation)作為事務(wù)特性的一個關(guān)鍵特性,它要求每個讀寫事務(wù)的對象對其他事務(wù)的操作對象能相互分離,即該事務(wù)提交前對其他事務(wù)都不可見,在數(shù)據(jù)庫層面都是使用鎖來實現(xiàn)。

事務(wù)的隔離級別從低到高有以下四種:

  • READ UNCOMMITTED(未提交讀):這是最低的隔離級別,其含義是允許一個事務(wù)讀取另外一個事務(wù)沒有提交的數(shù)據(jù)。READ UNCOMMITTED是一種危險的隔離級別,在實際開發(fā)中基本不會使用,主要是由于它會帶來臟讀問題。

    時間事務(wù)1事務(wù)2備注
    1讀取庫存為100------
    2扣減庫層50---剩余50
    3
    扣減庫層50---
    4
    提交事務(wù)庫存保存為0
    5回滾事務(wù)---事務(wù)回滾為0

臟讀對于要求數(shù)據(jù)一致性的應(yīng)用來說是致命的,目前主流的數(shù)據(jù)庫的隔離級別都不會設(shè)置成READ UNCOMMITTED。不過臟讀雖然看起來毫無用處,但是它主要優(yōu)點是并發(fā)能力高,適合那些對數(shù)據(jù)一致性沒有要求而追求高并發(fā)的場景。

  • READ COMMITTED(讀寫提交): 它是指一個事務(wù)只能讀取另外一個事務(wù)已經(jīng)提交的數(shù)據(jù),不能讀取未提交的數(shù)據(jù)。READ COMMITTED會帶來不可重復(fù)讀的問題:

時間事務(wù)1事務(wù)2備注
1讀取庫存為1

2扣減庫存
事務(wù)未提交
3
讀取庫存為1
4提交事務(wù)
庫存變成0
5
扣減庫存庫存為0,無法扣減

不可重復(fù)讀和臟讀的區(qū)別是:臟讀讀取到的是未提交的數(shù)據(jù),而不可重復(fù)讀讀到的確實已經(jīng)提交的數(shù)據(jù),但是違反了數(shù)據(jù)庫事務(wù)一致性的要求。

一般來說,不可重復(fù)讀的問題是可以接受的,因為其讀到的是已經(jīng)提交的數(shù)據(jù),本身并不會帶來很大的問題。因此,很多數(shù)據(jù)庫如(ORACLE,SQL SERVER)將其默認隔離級別設(shè)置為READ COMMITTED,允許不可重復(fù)讀的現(xiàn)象。

  • REPEATABLE READ (可重復(fù)讀):可重復(fù)讀的目標是為了克服READ COMMITED中出現(xiàn)的不可重復(fù)讀,它指在同一個事務(wù)內(nèi)的查詢都是與事務(wù)開始時刻一致,以上表為例,在REPEATABLE READ隔離級別下它會發(fā)生如下變化:

時間事務(wù)1事務(wù)2備注
1讀取庫存為1

2扣減庫存
事務(wù)未提交
3
讀取庫存不允許讀取,等待事務(wù)1提交
4提交事務(wù)
庫存變成0
5
讀取庫存庫存為0,無法扣減

REPEATABLE READ雖然解決了不可重復(fù)讀問題,但是他又會帶來幻讀問題,幻讀是指,在一個事務(wù)中,第一次查詢某條記錄,發(fā)現(xiàn)沒有,但是,當試圖更新這條不存在的記錄時,竟然能成功,并且,再次讀取同一條記錄,它就神奇地出現(xiàn)了。

時間事務(wù)A事務(wù)2備注
1beginbegin
2
讀取id為100的數(shù)據(jù)沒有數(shù)據(jù)
3插入id為100的數(shù)據(jù)

4提交事務(wù)

5
讀取id為100的數(shù)據(jù)沒有數(shù)據(jù)
6
更新id為100的數(shù)據(jù)成功
7
讀取id為100的數(shù)據(jù)讀取成功
8
提交事務(wù)

事務(wù)B在第2步第一次讀取id=99的記錄時,讀到的記錄為空,說明不存在id=99的記錄。隨后,事務(wù)A在第3步插入了一條id=99的記錄并提交。事務(wù)B在第5步再次讀取id=99的記錄時,讀到的記錄仍然為空,但是,事務(wù)B在第6步試圖更新這條不存在的記錄時,竟然成功了,并且,事務(wù)B在第8步再次讀取id=99的記錄時,記錄出現(xiàn)了。

  • SERIALIZABLE(串行化):數(shù)據(jù)庫最高的隔離級別,它要求所有的SQL都會按照順序執(zhí)行,這樣可以克服上述所有隔離出現(xiàn)的各種問題,能夠完全包住數(shù)據(jù)的一致性。

Spring中配置隔離級別

在Spring項目中配置隔離級別只需要做如下操作

@Transactional(isolation = Isolation.SERIALIZABLE)
public int insertUser(User user){
    return userDao.insertUser(user);
}

上面的代碼中我們使用了串行化的隔離級別來包住數(shù)據(jù)的一致性,這使它將阻塞其他的事務(wù)進行并發(fā),所以它只能運用在那些低并發(fā)而又需要保證數(shù)據(jù)一致性的場景下。

隔離級別字典:

DEFAULT(-1),  ## 數(shù)據(jù)庫默認級別
READ_UNCOMMITTED(1),
READ_COMMITTED(2),
REPEATABLE_READ(4),
SERIALIZABLE(8);

傳播行為

在Spring中,當一個方法調(diào)用另外一個方法時,可以讓事務(wù)采取不同的策略工作,如新建事務(wù)或者掛起當前事務(wù)等,這便是事務(wù)的傳播行為。

定義

在Spring的事務(wù)機制中對數(shù)據(jù)庫存在7種傳播行為,通過枚舉類Propagation定義。

public enum Propagation {
    /**
     * 需要事務(wù),默認傳播性行為。
     * 如果當前存在事務(wù),就沿用當前事務(wù),否則新建一個事務(wù)運行子方法
     */
    REQUIRED(0),
    /**
     * 支持事務(wù),如果當前存在事務(wù),就沿用當前事務(wù),
     * 如果不存在,則繼續(xù)采用無事務(wù)的方式運行子方法
     */
    SUPPORTS(1),
    /**
     * 必須使用事務(wù),如果當前沒有事務(wù),拋出異常
     * 如果存在當前事務(wù),就沿用當前事務(wù)
     */
    MANDATORY(2),
    /**
     * 無論當前事務(wù)是否存在,都會創(chuàng)建新事務(wù)允許方法
     * 這樣新事務(wù)就可以擁有新的鎖和隔離級別等特性,與當前事務(wù)相互獨立
     */
    REQUIRES_NEW(3),
    /**
     * 不支持事務(wù),當前存在事務(wù)時,將掛起事務(wù),運行方法
     */
    NOT_SUPPORTED(4),
    /**
     * 不支持事務(wù),如果當前方法存在事務(wù),將拋出異常,否則繼續(xù)使用無事務(wù)機制運行
     */
    NEVER(5),
    /**
     * 在當前方法調(diào)用子方法時,如果子方法發(fā)生異常
     * 只回滾子方法執(zhí)行過的SQL,而不回滾當前方法的事務(wù)
     */
    NESTED(6);
	......
}

日常開發(fā)中基本只會使用到REQUIRED(0),REQUIRES_NEW(3),NESTED(6)三種。

NESTEDREQUIRES_NEW是有區(qū)別的。NESTED傳播行為會沿用當前事務(wù)的隔離級別和鎖等特性,而REQUIRES_NEW則可以擁有自己獨立的隔離級別和鎖等特性。

NESTED的實現(xiàn)主要依賴于數(shù)據(jù)庫的保存點(SAVEPOINT)技術(shù),SAVEPOINT記錄了一個保存點,可以通過ROLLBACK TO SAVEPOINT來回滾到某個保存點。如果數(shù)據(jù)庫支持保存點技術(shù)時就啟用保存點技術(shù);如果不支持就會新建一個事務(wù)去執(zhí)行代碼,也就相當于REQUIRES_NEW。

Transactional自調(diào)用失效

如果一個類中自身方法的調(diào)用,我們稱之為自調(diào)用。如一個訂單業(yè)務(wù)實現(xiàn)類OrderServiceImpl中有methodA方法調(diào)用了自身類的methodB方法就是自調(diào)用,如:

@Transactional
public void methodA(){
    for (int i = 0; i < 10; i++) {
        methodB();
    }
}
    
@Transactional(isolation = Isolation.READ_COMMITTED,propagation = Propagation.REQUIRES_NEW)
public int methodB(){
    ......
}

在上面方法中不管methodB如何設(shè)置隔離級別和傳播行為都是不生效的。即自調(diào)用失效。

這主要是由于@Transactional的底層實現(xiàn)原理是基于AOP實現(xiàn),而AOP的原理是動態(tài)代理,在自調(diào)用的過程中是類自身的調(diào)用,而不是代理對象去調(diào)用,那么就不會產(chǎn)生AOP,于是就發(fā)生了自調(diào)用失敗的現(xiàn)象。

要克服這個問題,有2種方法:

  • 編寫兩個Service,用一個Service的methodA去調(diào)用另外一個Service的methodB方法,這樣就是代理對象的調(diào)用,不會有問題;

  • 在同一個Service中,methodA不直接調(diào)用methodB,而是先從Spring IOC容器中重新獲取代理對象`OrderServiceImpl·,獲取到后再去調(diào)用methodB。說起來有點亂,還是show you the code。

public class OrderServiceImpl implements OrderService,ApplicationContextAware {
    private ApplicationContext applicationContext = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Transactional
    public void methodA(){
        OrderService orderService = applicationContext.getBean(OrderService.class);
        for (int i = 0; i < 10; i++) {
            orderService.methodB();
        }
    }

    @Transactional(isolation = Isolation.READ_COMMITTED,propagation = Propagation.REQUIRES_NEW)
    public int methodB(){
        ......
    }

}

上面代碼中我們先實現(xiàn)了ApplicationContextAware接口,然后通過applicationContext.getBean()獲取了OrderService的接口對象。這個時候獲取到的是一個代理對象,也就能正常使用AOP的動態(tài)代理了。

回到最開始的那個問題,看完這篇文章是不是有答案了呢?

到此,關(guān)于“Spring的事務(wù)隔離級別與傳播性是什么意思”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI