數據庫事務相關記錄

數據庫事務的特性    

    1.原子性 A  事務是不可分割的最小單元,事務內的操作要麼全部操作,要麼全部不操作,不能只做一部分。
    2.一致性 C  事務執行前數據庫數據的正確狀態要保持到事務執行後,和原子性的操作有異曲同工之妙。
    3.隔離性 I  所謂隔離性就是事務之間的隔離性,一個事物內部的操作是不能被其他事物影響,通過事物的隔離界別來完成,沒有隔離性就一定會有下面的四種問題。
    4.持久性 D  事務一旦提交,數據就永久性被修改了。
多線程操作事務,如果不加任何限制,會出現如下的問題:
    1.丟失更新

    丟失更新更爲兩種情況
    1.1 第一類丟失更新
        也稱作回滾丟失,Lost Update。
        可以簡單的理解成:                        
        事物A和事物B同時讀取數據X=100,A進行了X=X+100的操作,然後提交事務。B進行了X=X-100的操作,然後又事務回滾了,
        回滾後按照正常思維X回到原來讀到的數據1000,
        這就把A的提交操作覆蓋了,這種就是第一類丟失跟新,所有數據的任何隔離界別都默認解決了這種情況。
        即:即便此時B回滾,數據也還是A提交之後的200,而不會變成100.
    1.2 第二類丟失更新
        也稱作覆蓋更新或者兩次更新的問題,Second lost update
        可接簡單的理解成:
        事物A和事物B同時都獲取了數據X=100,事物A對X進行+100的修改,然後提交,結果是200.但是事物B對X進行了加200操作,最後提交結果是300.
        A和B誰最後提交,那麼X的結果就是誰,反而早提交的事物就丟失了此次更新。
    2.髒數據
        所謂髒數據,是指A事務正在訪問數據庫,並對數據進行了修改,但是還沒提交,這時候事務B也訪問了這個被修改的數據,
        因爲A還沒提交,所以B讀到的就是髒數據,這個數據有可能是不正確的。
        PS:正常情況下,髒數據在Mysql/Oracle的默認級別中是不會出現的,是能是同一個事務內的操作可以互相讀取這樣的數據。
    3.不可重複讀
        所謂不可重複讀可以簡單理解爲:事物A和事物B同時獲取數據X=100,然後事物B修改X=X+100然後提交,在事物A中如果重新讀取X會發現已經變成200了,
        和第一次讀取的X值不一樣。區別於髒讀的點在於事物B提交後事物A再讀取時,無法獲取第一次查詢的數據,估稱之爲不可重複讀。
    4.幻讀
        所謂幻讀,可以簡單理解成:事物A在讀取數據符合某一條件的過程中事物B又提交了符合條件的數據,事物A就會出現兩次讀的數據不一樣,可能少可能多。
        和不可重複很類似,都是事物A讀取的數據被事物B調整了,區別在於操作上不同,不可重複讀是update,幻讀是insert和delete,
        但是如果數據庫隔離級別設置的很低,從某種意義上說幻讀也是包括不可重複讀的。
     
    注意點:
        以上幾種情況,有一個前提,不管事務A還是事務B,出現這問題都是在一個事務內部,及事務還沒提交的時候。
        例如:關於不可重複讀,事務A讀取的數據第一次顯示100,第二次一刷新突然變成200了,這算不算不可重複讀?
        這肯定不算,這是兩次完整的操作,不涉及這樣的問題。這些問題的操作細節比實際開發中的業務問題要細緻的多。

以上四種情況是多線程操作數據庫時候直觀上不可避免會出現的問題,針對這些問題,我們引入數據可隔離級別、共享鎖、排它鎖、互斥鎖、樂觀鎖、悲觀鎖等等。還要搞清楚什麼情況下開啓事物,例如:在SpringBoot的開發中,如果單單是查詢也開啓了事物有什麼影響?不開啓僅僅依靠數據可的默認隔離界別又有什麼區別?
下面我們來一一瞭解和記錄。


數據庫隔離級別

   1.未提交讀  read_uncommited
        不隔離事務,不安全,只能解決第一類丟失問題,其他問題都不能解決,一般情況下我們都是不用的,除非不涉及修改操作。對應的是一級封鎖協議。
        【X鎖】
    2.提交讀    read_committed
        事務A只能讀到事務B已經提交的數據,沒提交的數據看不到,這種情況可以限制髒讀和第一類丟失問題,其他問題不能解決。oracle默認情況下是提交讀的隔離級別。
        也就是說事務在準備讀取數據X的時候,會給他加一個共享鎖,對應的是二級加鎖協議。
        【X鎖+臨時S鎖】
    3.可重複讀  repeatable read
        顯而易見,可重複讀可以解決不可重複讀的問題,但是無法解決幻讀的情況。
        他指的是:保證同一個事物中先後執行的多次查詢結果一致。也就是說,某個事務讀取數據X後,在該事物結束事務前,任何其他事務都不能修改這個數據。
        對應的也是數據庫的三級加鎖協議。
        【X鎖+持續S鎖】
    4.序列化    serializable
        最高級別,不允許事務併發執行。

   1.樂觀鎖
        所謂樂觀鎖,可以簡單理解爲:所有事物都可以讀寫,在寫的時候會判斷下數據是否發生變化了,
        即:是否出現了不可重複讀的情況,如果出現,就回滾事務。數據更新之前使用
        舊數據校驗一下,例如:update tablea set dl='2' where dl='3'(同樣的,我們也可以使用獨立的時間戳字段區分不同版本來完成樂觀鎖)
    2.悲觀鎖
        共享鎖(S鎖)
        被加了S鎖的數據,可以被其他事物讀,但是不能寫,對於添加S鎖的事務本身,也是隻能讀不可寫,且其他事物也不能給數據再添加X鎖。
        排它鎖(X鎖)
        被加了X鎖的數據,只能被添加鎖的事物讀寫,其他事務不能操作,也不能再添加鎖。


關於封鎖協議

    1.一級封鎖協議
        事務T在修改數據R之前必須先對其進行加X鎖,直到事務T結束才釋放。
    2.二級封鎖協議
        在一級封鎖協議的基礎上增加事務T在讀取數據R之前必須先對其加S鎖,讀完後即可釋放S鎖。 臨時S鎖
    3.三級封鎖協議
        在一級封鎖協議的基礎上增加事務T在讀取數據R之前必須先對其加S鎖,直到事務結束才釋放。持久S鎖
    注意點:
        乍一看,直接使用一級封鎖協議完全使用X鎖不就好了?
        其實有個概念要理清楚,那就是一級封鎖協議添加X鎖後,其事務在操作的時候,可以不加鎖了,不加鎖常規操作就能直接查詢,
        所以不可避免的出現髒讀、不可重複讀這些問題。二級、三級封鎖協議的前提是事務操作前要加S鎖,這是關鍵,問題是加了X鎖的數據就不能加S鎖了,所以限制性比較高。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章