淺談:髒讀、幻讀、不可重複讀以及事務隔離級別

髒讀:指當一個事務正在訪問數據,並且對應一部分數據進行了操作但還未提交更新到數據庫,此時另一個事務正在讀取數據其中其中就包含修改的數據,且使用了這部分數據。

例子:

1、張三原先考試成績爲59分,A老師想提高合格率將張三的大題給了同情分1分,分數變爲了60分,但是還未提交到數據庫;

2、張三網上查看自己的分數時爲60分,及格了非常開心;

3、A老師覺得此事辦的欠妥,於是回滾了數據事務。

那麼張三看到的那個60分就是髒讀數據。

 

幻讀指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的數據進行了修改,這種修改涉及到表中的全部數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那麼,以後就會發生操作第一個事務的用戶發現表中還有沒有修改的數據行,就好象發生了幻覺一樣。

舉例:
   目前工資爲1000的員工有10人。
   1.事務1,讀取所有工資爲1000的員工。
   2.這時事務2向employee表插入了一條員工記錄,工資也爲1000
   3.事務1再次讀取所有工資爲1000的員工 共讀取到了11條記錄, 
  解決辦法:如果在操作事務完成數據處理之前,任何其他事務都不可以添加新數據,則可避免該問題。

 

不可重複讀是指在一個事務內,多次讀同一數據。在這個事務還沒有結束時,另外一個事務也訪問該同一數據。那麼,在第一個事務中的兩次讀數據之間,由於第二個事務的修改,那麼第一個事務兩次讀到的的數據可能是不一樣的。這樣在一個事務內兩次讀到的數據是不一樣的,因此稱爲是不可重複讀。

舉例:

    1.在事務1中,張三讀取了自己的分數爲90,操作並沒有完成;
    2.在事務2中,這時李老師修改了張三的分數爲95,並提交了事務;
    3.在事務1中,張三再次讀取自己的工資時,分數變爲了90。

解決辦法:如果只有在修改事務完全提交之後纔可以讀取數據,則可以避免該問題。

2、在一個程序中,依據事務的隔離級別將會有三種情況發生。
  髒讀:一個事務會讀進還沒有被另一個事務提交的數據,所以你會看到一些最後被另一個事務回滾掉的數據。
  不可重複讀:一個事務讀進一條記錄,另一個事務更改了這條記錄並提交完畢,這時候第一個事務再次讀這條記錄時,它已經改變了
  幻讀:一個事務用Where子句來檢索一個表的數據,另一個事務插入一條新的記錄,並且符合Where條件,這樣,第一個事務用同一個where條件來檢索數據後,就會多出一條記錄

3、數據庫提供了四種事務隔離級別, 不同的隔離級別採用不同的鎖類開來實現. 
在四種隔離級別中, Serializable的級別最高, Read Uncommited級別最低. 
大多數數據庫的默認隔離級別爲: Read Commited,如Sql Server , Oracle. 
少數數據庫默認的隔離級別爲Repeatable Read, 如MySQL InnoDB存儲引擎

SQL SERVER鎖的機制 
        SQL server的所有活動都會產生鎖。鎖定的單元越小,就越能越能提高併發處理能力,但是管理鎖的開銷越大。如何找到平衡點,使併發性和性能都可接受是SQL Server的難點。
SQL Server有如下幾種瑣:
         SQL server的所有活動都會產生鎖。鎖定的單元越小,就越能越能提高併發處理能力,但是管理鎖的開銷越大。如何找到平衡點,使併發性和性能都可接受是SQL Server的難點。


SQL Server有如下幾種瑣:

1、 共享鎖
用於只讀操作(SELECT),鎖定共享的資源。共享鎖不會阻止其他用戶讀,但是阻止其他的用戶寫和修改。

2、 更新鎖
更新鎖是一種意圖鎖,當一個事務已經請求共享瑣後並試圖請求一個獨佔鎖的時候發生更新瑣。例如當兩個事務在幾行數據行上都使用了共享鎖,並同時試圖獲取獨佔鎖以執行更新操作時,就發生了死鎖:都在等待對方釋放共享鎖而實現獨佔鎖。更新鎖的目的是隻讓一個事務獲得更新鎖,防止這種情況的發生。

3、 獨佔鎖
一次只能有一個獨佔鎖用在一個資源上,並且阻止其他所有的鎖包括共享縮。寫是獨佔鎖,可以有效的防止’髒讀’。

4、 意圖縮
在使用共享鎖和獨佔鎖之前,使用意圖鎖。從表的層次上查看意圖鎖,以判斷事務能否獲得共享鎖和獨佔鎖,提高了系統的性能,不需從頁或者行上檢查。

5、 計劃鎖
Sch-M,Sch-S。對數據庫結構改變時用Sch-M,對查詢進行編譯時用Sch-S。這兩種鎖不會阻塞任何事務鎖,包括獨佔鎖。
讀是共享鎖,寫是排他鎖,先讀後更新的操作是更新鎖,更新鎖成功並且改變了數據時更新鎖升級到排他鎖

l     DEFAULT 使用數據庫設置的隔離級別 ( 默認 ) ,由 DBA 默認的設置來決定隔離級別 . 
l     READ_UNCOMMITTED 會出現髒讀、不可重複讀、幻讀 ( 隔離級別最低,併發性能高 ) 
l     READ_COMMITTED  會出現不可重複讀、幻讀問題(鎖定正在讀取的行) 
l     REPEATABLE_READ 會出幻讀(鎖定所讀取的所有行) 
l     SERIALIZABLE 保證所有的情況不會發生(鎖表


ReadCommitted: 
假設A事務對正在讀取數據Data放置了共享鎖,那麼Data不能被其它事務改寫,所以當B事務對Data進行讀取時總和A讀取的Data數據是一致的,所以避免了髒讀。由於在A沒有提交之前可以對Data進行改寫,那麼B讀取到的某個值可能會在其讀取後被A更改從而導致了該值不能被重複取得;或者當B再次用相同的where字句時得到了和前一次不一樣數據的結果集,也就是幻像數據。

ReadUncommitted:
假設A事務即不發佈共享鎖,也不接受獨佔鎖,那麼併發的B或者其它事務可以改寫A事務讀取的數據,那麼併發的C事務讀取到的數據的狀態和A的或者B的數據都可能不一致,那麼。髒讀、不可重複讀、幻象數據都可能存在。

RepeatableRead:
(注意MSDN原文中的第一句話:在查詢中使用的所有數據上放置鎖,所以不存在髒讀的情況)。
假設A事務對讀取的所有數據Data放置了鎖,以阻止其它事務對Data的更改,在A沒有提交之前,新的併發事務讀取到的數據如果存在於Data中,那麼該數據的狀態和A事務中的數據是一致的,從而避免了不可重複的讀取。但在A事務沒有結束之前,B事務可以插入新記錄到Data所在的表中,那麼其它事務再次用相同的where字句查詢時,得到的結果數可能上一次的不一致,也就是幻像數據。

Serializable:
 在數據表上放置了排他鎖,以防止在事務完成之前由其他用戶更新行或向數據集中插入行,這是最嚴格的鎖。它防止了髒讀、不可重複讀取和幻象數據。

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