資料庫併發問題與隔離級別
1 併發產生的問題
資料庫的事務在併發執行的時候,如果不考慮隔離性,就會產生以下幾種問題:
1.1 髒讀
髒讀是指在一個事務處理過程裡讀取了另一個未提交的事務中的資料。
假設事務1正在訪問資料並且對資料進行了修改,而這種修改還沒有提交到資料庫中,這時,事務2也訪問這個資料,然後使用了這個資料。因為這個資料是還沒有提交的資料,那麼事務2讀到的這個資料是儲存在資料庫記憶體中的資料,稱為髒讀。讀到的資料為髒資料,依據髒資料所做的操作可能是不正確的
1.2 不可重複讀
不可重複讀是指在對於資料庫中的某個資料,一個事務範圍內多次查詢卻返回了不同的資料值,這是由於在查詢間隔,被另一個事務修改並提交了。
在事務1內,多次讀同一個資料。在事務1還沒有結束時,事務2也訪問該同一資料並修改資料。那麼,在事務1的兩次讀資料之間。由於事務2的修改,那麼事務1兩次讀到的資料可能不一樣,這樣就發生了在一個事務內兩次讀到的資料是不一樣的,因此稱為不可重複讀,即原始讀取不可重複。
相比起髒讀,不可重複讀讀取的是另一個已經提交的事務,而髒讀讀取的是還未提交的事務。
在某些情況下,不可重複讀並不是問題,比如我們多次查詢某個資料當然以最後查詢得到的結果為主。但在另一些情況下就有可能發生問題,例如對於同一個資料A和B依次查詢就可能不同,從而引發錯誤
1.3 幻讀
幻讀是指當事務不是獨立執行時發生的一種現象。例如事務T1對一個表中所有的行的某個資料項做了從“1”修改為“2”的操作,這時事務T2又對這個表中插入了一行資料項,而這個資料項的數值還是為“1”並且提交給資料庫。而操作事務T1的使用者如果再檢視剛剛修改的資料,會發現還有一行沒有修改,其實這行是從事務T2中新增的,就好像產生幻覺一樣,這就是發生了幻讀。
幻讀和不可重複讀都是讀取了另一條已經提交的事務(這點就髒讀不同),所不同的是不可重複讀查詢的都是同一個資料項,而幻讀針對的是一批資料整體(比如資料的個數)
2 資料庫的隔離級別
為了避免以上問題,防止事務被其他事務干擾,因此多個併發的事務之間需要相互隔離。隔離等級分為4個級別,由低到高分別是為:
2.1 讀未提交(Read uncommitted)
允許讀取未提交的資料。此時,可能會發生髒讀、不可重複讀、幻讀。這是併發最高,但也是一致性最差的隔離級別
2.2 讀已提交(Read committed)
只允許讀取已提交的資料。可以避免髒讀,但無法避免不可重複讀和幻讀
2.3 可重複讀(Repeatable read)
只允許讀取已提交的資料,並且在一個事務兩次讀取一個數據項期間,其他事務不得更新資料。可以避免髒讀和不可重複讀,無法避免幻讀。這也是MySQL預設的隔離級別
2.4 序列化(Serializable )
保證所有的事務序列化排程。這種隔離級別可以避免髒讀、不可重複讀、幻讀
以表格形式整理:
隔離級別 | 是否存在髒讀 | 是否存在不可重複讀 | 是否存在幻讀 |
---|---|---|---|
讀未提交 | 是 | 是 | 是 |
讀已提交 | 否 | 是 | 是 |
可重複讀 | 否 | 否 | 是 |
序列化 | 否 | 否 | 否 |