天天看點

事務的隔離級别?幻讀和不可重複的差別

文章目錄

        • 一 定義
        • 二 解釋
          • Read-Uncommited(讀未送出)
          • Read-commited(讀已送出)
          • Repeatable-Read(可重複讀)
          • Serializable(串行化)
        • 三 什麼是不可重複讀,什麼是幻讀
          • 不可重複讀
          • 幻讀

一 定義

mysql的事務隔離級别一共有四個:

  • 讀未送出(Read-Uncommited),
  • 讀已送出(Read-Commited),
  • 可重複讀(Repeatable-Read) ,
  • 串行化(Serializable) 。

其中,MySQL的預設的事務隔離級别為可重複讀(Repeatable-Read)。

二 解釋

簡單的介紹一下四種隔離級别:

Read-Uncommited(讀未送出)

在Read Uncommited級别,事務中的修改,即便沒有送出,對其他事務也都是可見的,事務可以讀取未送出的資料,這也是被叫做髒讀(Dirty Read),這種級别會導緻很多問題,從性能上看,Read Uncommited不會比其他的級别好太多,但缺乏其他事務級别的很多好處,除非真的非常有必要的理由,在實際應用中,一般最好不要使用

Read-commited(讀已送出)

大多數資料庫系統的預設隔離級别都是Read Commited(Oracle,但是Mysql不是),Read Commited滿足事務隔離級别的一般定義,一個事務開始時,隻能看到已經送出的事務所做的修改,換句話說,一個事務從開始到送出之前,所做的任何修改對其他事務都是不可見的,這種級别有時候也叫不可重複讀,因為兩次執行同樣的查詢,可能會得到不一樣的結果。

Repeatable-Read(可重複讀)

Repeatable-Read解決了髒讀的問題,該級别保證了在同一個事務中多次讀取同樣記錄的結果是一緻的,但是理論上,可重複讀隔離級别還是無法解決另一種幻讀(Phantom Read)的問題,所謂幻讀,指的是當某個事務在讀取某個範圍内的記錄時,另外一個事務又在該範圍内插入了新的記錄,當之前的事務再次讀取該範圍的記錄時,會出現幻行(Phantom Row),Innodb和XtraDB存儲引擎通過多版本并發控制(MVCC ,multuversion concurrencyControl)解決了幻讀的問題,

該級别是Mysql的預設的事務隔離級别

Serializable(串行化)

Serializable是最高的隔離級别,它通過強制事務串行執行,避免了前面說的幻讀問題,簡單來說,Serializable會在讀取的每一行資料上都加鎖,是以可能導緻大量的逾時和鎖競争的問題,實際應用中也是很少使用到這種隔離級别,隻有在非常需要保證資料的一緻性而且可以接收沒有并發的情況下,才考慮使用該事務的隔離級别。

三 什麼是不可重複讀,什麼是幻讀

在去實際區分這兩個定義之前,我們先去了解一下定義:

  • 髒讀(Diry Read)實際上在上面個的定義中,已經說明:事務中的修改,即便沒有送出,對其他事務也都是可見的,事務可以讀取未送出的資料,這也是被叫做髒讀
  • 不可重複讀:同一事務的兩次同樣的操作執行,會的到不同的結果
  • 幻讀:指的是當某個事務在讀取某個範圍内的記錄時,另外一個事務又在該範圍内插入了新的記錄,當之前的事務再次讀取該範圍的記錄時,會出現幻行
不可重複讀

檢視mysql目前預設的事務隔離級别:

# 表示查詢目前會話的事務隔離級别
select @@tx_isolation;
# 表示查詢目前全局範圍内mysql的事務隔離級别
select @@global.tx_isolation;
           
事務的隔離級别?幻讀和不可重複的差別

1,首先示範,設定目前全局mysql的事務隔離級别為讀已送出(Read-commited)

//設定read uncommitted級别:
set session transaction isolation level read uncommitted;

//設定read committed級别:
set session transaction isolation level read committed;

//設定repeatable read級别:
set session transaction isolation level repeatable read;

//設定serializable級别:
set session transaction isolation level serializable;
           

2,設定事務手動送出,并且在事務A中第一次查詢user_info表的school字段資料,然後再B事務中修改user_info表中的school字段資料,同時送出事務,這個時候再在A事務中查詢user_info表中的school字段資料,會發現兩次同樣的查詢語句對應的結果不一緻

A事務:

事務的隔離級别?幻讀和不可重複的差別

B事務:

事務的隔離級别?幻讀和不可重複的差別
幻讀

1,修改mysql的事務隔離級别為可重複讀,同樣執行上面的操作,

A事務:

事務的隔離級别?幻讀和不可重複的差別

B事務:

事務的隔離級别?幻讀和不可重複的差別

此時我們會發現REPEATABLE-READ事務隔離級别是解決了不可重複讀,即A事務中,同樣的執行語句無論B事務是否對其進行修改并送出事務,A事務中的查詢語句結果都是一緻的。

注:在《高性能Mysql》一書中,關于什麼是幻讀進行了這樣的講解:

事務的隔離級别?幻讀和不可重複的差別

所謂幻讀,指的是當某個事務在讀取某個範圍内的記錄時,另外一個事務又在該範圍内插入了新的記錄,當之前的事務再次讀取該範圍的記錄時,會産生幻行。InnoDB存儲引擎通過多版本并發控制(MVCC)解決了幻讀的問題。

但是:RR的事務隔離級别并沒有解決另一種通常意義上說的也是幻讀現象,那就是insert的情況

舉例:

對于A事務,我們查詢user_info表中沒有對應的浙江大學的school,對于B事務,我們任然在事務中查詢不到對應的浙江大學的school,這個時候,我們在A事務中首先建立了一個school為浙江大學的一列資料并送出事務,此時B事務中根據REPEATABLE-READ事務隔離級别任然是不會查詢到school為浙江大學的一列資料,這個時候我們再在B事務中插入一個school為浙江大學的一列,因為我們在school字段加了唯一索引,這個時候就會出現B事務插入shcool資料重複的問題:

A事務

事務的隔離級别?幻讀和不可重複的差別

B事務:

事務的隔離級别?幻讀和不可重複的差別