1. 程式人生 > >事務隔離性等級

事務隔離性等級

資料庫沒有隔離性時會出現的情況:

當多個執行緒都開啟事務操作資料庫中的資料時,資料庫系統要能進行隔離操作,以保證各個執行緒獲取資料的準確性,在介紹資料庫提供的各種隔離級別之前,我們先看看如果不考慮事務的隔離性,會發生的幾種問題:

1,髒讀

髒讀是指在一個事務處理過程裡讀取了另一個未提交的事務中的資料。

當一個事務正在多次修改某個資料,而在這個事務中這多次的修改都還未提交,這時一個併發的事務來訪問該資料,就會造成兩個事務得到的資料不一致。例如:使用者A向用戶B轉賬100元,對應SQL命令如下

update account set money=money+100 where name=’B’;  (此時A通知B)

update account set money=money - 100 where name=’A’;

當只執行第一條SQL時,A通知B檢視賬戶,B發現確實錢已到賬(此時即發生了髒讀),而之後無論第二條SQL是否執行,只要該事務不提交,則所有操作都將回滾,那麼當B以後再次檢視賬戶時就會發現錢其實並沒有轉。

2,不可重複讀

不可重複讀是指在對於資料庫中的某個資料,一個事務範圍內多次查詢卻返回了不同的資料值,這是由於在查詢間隔,被另一個事務修改並提交了。

例如事務T1在讀取某一資料,而事務T2立馬修改了這個資料並且提交事務給資料庫,事務T1再次讀取該資料就得到了不同的結果,傳送了不可重複讀。

不可重複讀和髒讀的區別是,髒讀是某一事務讀取了另一個事務未提交的髒資料,而不可重複讀則是讀取了前一事務提交後

的資料。

在某些情況下,不可重複讀並不是問題,比如我們多次查詢某個資料當然以最後查詢得到的結果為主。但在另一些情況下就有可能發生問題,例如對於同一個資料A和B依次查詢就可能不同,A和B就可能打起來了……

3,虛讀(幻讀)

幻讀是事務非獨立執行時發生的一種現象。
例如事務T1對一個表中所有的行的某個資料項做了從“1”修改為“2”的操作,這時事務T2又對這個表中插入了一行資料項,而這個資料項的數值還是為“1”並且提交給資料庫。而操作事務T1的使用者如果再檢視剛剛修改的資料,會發現還有一行沒有修改,其實這行是從事務T2中新增的,就好像產生幻覺一樣,這就是發生了幻讀。

幻讀和不可重複讀都是讀取了另一條已經提交的事務(這點就髒讀不同),所不同的是不可重複讀查詢的都是同一個資料項,而幻讀針對的是一批資料整體(比如資料的個數)。

隔離級別:

現在來看看四種隔離級別:

Serializable (序列化):可避免髒讀、不可重複讀、幻讀的發生。
序列化,最高的事務隔離級別,不管多少事務,挨個執行完一個事務的所有子事務之後才可以執行另外一個事務裡面的所有子事務,這樣就解決了髒讀、不可重複讀和幻讀的問題了

Repeatable read (可重複讀):可避免髒讀、不可重複讀的發生。
重複讀取,即在資料讀出來之後加鎖,類似"select * from XXX for update",明確資料讀取出來就是為了更新用的,所以要加一把鎖,防止別人修改它。REPEATABLE_READ的意思也類似,讀取了一條資料,這個事務不結束,別的事務就不可以改這條記錄,這樣就解決了髒讀、不可重複讀的問題,但是幻讀的問題還是無法解決

Read committed (讀已提交):可避免髒讀的發生。
讀已提交,即能夠讀到那些已經提交的資料,自然能夠防止髒讀,但是無法限制不可重複讀和幻讀

Read uncommitted (讀未提交):最低級別,任何情況都無法保證。
讀未提交,即能夠讀取到沒有被提交的資料,所以很明顯這個級別的隔離機制無法解決髒讀、不可重複讀、幻讀中的任何一種,因此很少使用。

Mysql資料庫的隔離級別:

在使用InnoDB引擎的Mysql資料庫中,支援上面四種隔離級別,預設的為Repeatable read (可重複讀);而在Oracle資料庫中,只支援Serializable (序列化)級別和Read committed (讀已提交)這兩種級別,其中預設的為Read committed級別。

  • 檢視mysql資料庫的隔離級別:select @@tx_isolation;
    在這裡插入圖片描述

  • 在MySQL資料庫中設定事務的隔離:set transaction isolation level 隔離級別名稱;

  • 修改當前會話事務隔離級別使用SET session TRANSACTION ISOLATION LEVEL 隔離級別;, 只針對這一次拿到的Session有效。

  • 修改全域性事務隔離級別使用SET global TRANSACTION ISOLATION LEVEL 隔離級別;, 針對此後所有的會話有效,當前已經存在的會話不受影響。
    注意:設定資料庫的隔離級別一定要是在開啟事務之前!

隔離級別的有效範圍

隔離級別的設定只對當前連結有效。對於使用MySQL命令視窗而言,一個視窗就相當於一個連結,當前視窗設定的隔離級別只對當前視窗中的事務有效;對於JDBC操作資料庫來說,一個Connection物件相當於一個連結,而對於Connection物件設定的隔離級別只對該Connection物件有效,與其他連結Connection物件無關。

隔離是依賴於行級鎖

由於InnoDB引擎是支援事務,行級鎖和外來鍵的原因,事務的隔離性才能依賴行級鎖帶來的隔離功能。
隔離性和行級鎖的作用效應,可參考 隔離和鎖的關係