高性能MySQL學習筆記(4) —— 事務隔離級別

事務隔離級別

  事務的ACID屬性中的隔離性,如何實現呢?在SQL標準中定義了四種隔離級別。
  但要注意,標準中定義的這四個級別,在實際上各個存儲引擎的實現是不盡相同的,有些細節地方還是不一樣的,學習的時候需要注意下。
  有關事務的ACID屬性詳見:數據庫事務

併發問題

  在說明事務隔離級別之前,先說說事務併發可能引發的問題。
  1、更新丟失:一個事務的更新覆蓋了另一個事務的更新。事務A:向銀行卡存錢100元。事務B:向銀行卡存錢200元。A和B同時讀到銀行卡的餘額,分別更新餘額,後提交的事務B覆蓋了事務A的更新,這樣無形中就損失了100元。

  2、髒讀:一個事務讀取了另一個事務未提交的數據。事務A:張三妻子給張三轉賬100元。事務B:張三查詢餘額。事務A轉賬後(還未提交),事務B查詢多了100元。事務A由於某種問題,比如超時,進行回滾,這個時候事務B查詢到的數據是假數據。(防止不了select操作)

  3、不可重複讀:一個事務兩次讀取同一個數據,兩次讀取的數據不一致。事務A:張三妻子給張三轉賬100元。事務B:張三兩次查詢餘額。事務B第一次查詢餘額,事務A還沒有轉賬,第二次查詢餘額,事務A已經轉賬了,導致一個事務中,兩次讀取同一個數據,讀取的數據不一致。(防止不了update操作)

  4、幻象讀:一個事務兩次讀取一個範圍的記錄,兩次讀取的記錄數不一致。事務A:張三妻子兩次查詢張三有幾張銀行卡。事務B:張三新辦一張銀行卡。事務A第一次查詢銀行卡數的時候,張三還沒有新辦銀行卡,第二次查詢銀行卡數的時候,張三已經新辦了一張銀行卡,導致兩次讀取的銀行卡數不一樣。(防止不了insert/delete操作)

隔離級別

  事務的隔離級別和數據庫併發性是對立的,兩者此增彼長。以下隔離級別程度由低到高,併發性也就從高到低。隔離級別的設置是根據解決以上問題而依次設立的。

1.未提交讀

  Read uncommited:如果一個事務已經開始修改數據,則另外一個事務不允許同時進行修改操作,但允許其他事務讀此行數據,即事務中的修改,即使沒有提交,對其他的事務也是可見的,也就是說其他事務不可修改但可以讀取該事務未提交的數據,這種級別解決了更新丟失問題,但第2、3、4種問題都會出現,最不安全,一般不予採用。
  可以這樣理解:未提交讀是把事務每一步結果寫到了數據庫中,這個時候別的事務不能修改但可以“看到”,從而取到了“髒數據”。一般情況下,中間結果是不能直接寫到數據庫中被其他事務看到的。
總結:該級別防止了一個事務修改數據的同時另一個事務修改(對同一數據,下同),沒防止修改的同時讀(即僅對修改加了共享鎖)。

2.提交讀

  Read commited:事務結束之前,未提交之前,其他事務看到的數據是未執行該事務的值,即事務所做的任何修改對其他事務是不可見的,這個事務也叫不可重複讀(nonrepeatable read),是大多數數據庫系統默認的隔離級別(但MySQL不是)。

//事務A
{
    1:訪問x   //1
    2:訪問x   //2
}
//事務B
{
    修改x    //3
}

  兩個事務同時執行,順序爲:132,出現前後兩次訪問x值不同問題。(這裏的3不是中間結果,是已提交結果。)
  不可重複讀解決了更新丟失、髒讀,但不能解決不可重複讀和幻讀問題。
總結:該級別防止了一個事務修改的同時另一個事務修改,也防止修改的同時讀,但沒防止讀的時候修改(即僅對修改加了排它鎖)。

3.可重複讀

  Repeatable read,MySQL默認隔離級別,可以解決以上第1、2、3問題,但不能解決“幻讀”問題,可重複讀的做法是:讀哪幾行記錄時候,加鎖,這樣其他事務就不能修改了,多次讀的數據當然就一樣了,但是,假如這個時候有新增操作,新增的數據符合讀的條件,再次讀就會多出條數據,對於這個事務來說就好像出現了幻覺,就是所謂的“幻讀”。
總結:該級別防止了一個事務修改的同時另一個事務修改,也防止修改的同時讀,也防止讀的時候修改,但沒防止讀的時候新增/刪除(對影響的數據行的修改、讀加了排它鎖,沒對錶進行加鎖,解決幻讀,不一定要對錶加鎖,即隔離級別變爲4,也可以通過MVCC解決)。

4.可串行化

  Serializable,最高的隔離級別,所有事務串行執行,這樣不能併發,當然就沒有併發所帶來的問題,這是一種極端做法,實際應用很少用到,只有在非常需要數據一致性且可以接受無併發的情況下采用。
總結:表加鎖。

總結

  以上四個級別依次解決的問題的實質:修改時候同時修改、修改的時候同時讀、讀的時候同時修改、讀的時候同時新增/刪除。

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