隔离级别
自從知道事務的隔離級別已經很長時間了,一直處于半理解的狀態,這幾天看了很多的博客,對隔離級別有了更深的了解,覺得很有必要把自己的理解寫下來。
1.首先我們要知道為什么事務要分隔離級別。
如果沒有隔離級別的話,數據庫操作過程中會出現一下狀況
更新丟失(Lost update)
兩個事務都同時更新一行數據,但是第二個事務卻中途失敗退出,導致對數據的兩個修改都失效了。這是因為系統沒有執行任何的鎖操作,因此并發事務并沒有被隔離開來。
臟讀(Dirty Reads)
一個事務開始讀取了某行數據,但是另外一個事務已經更新了此數據但沒有能夠及時提交。這是相當危險的,因為很可能所有的操作都被回滾。
不可重復讀(Non-repeatable Reads)
一個事務對同一行數據重復讀取兩次,但是卻得到了不同的結果。它包括以下情況:
(1) 事務T1讀取某一數據后,事務T2對其做了修改,當事務T1再次讀該數據時得到與前一次不同的值。
(2) 幻讀(Phantom Reads):事務在操作過程中進行兩次查詢,第二次查詢的結果包含了第一次查詢中未出現的數據或者缺少了第一次查詢中出現的數據(這里并不要求兩次查詢的SQL語句相同)。這是因為在兩次查詢過程中有另外一個事務插入數據造成的。
可能有些人看到這些概念會有似是而非的感覺,為了能讓大家更好的理解這些概念,下面我們通過例子說明這幾種情況
Create Table Student
(
Name varchar(50),
Age int,
Address varchar(50)
)
Insert into Student values('小明',15,'北京')
Insert into Student values('小王',16,'天津')
a.更新丟失
有兩個事務T1 和T2
T1操作為
update student set Age = 16 where name ='小明'
T2操作為
update student set Address = '武漢' where name ='小明'
T1 與T2同是開始,也就是T1和T2這兩個事務開始的時候 小明信息為('小明',15,'北京')
T1成功,小明信息更改為 ('小明',16,'北京');
T2失敗,事務回滾到操作之前的狀態 小明信息變為('小明',15,'北京')
T2的失敗造成T1的更新丟失,這就叫做更新丟失,避免更新丟失的方法就是加排他寫鎖,排他寫鎖就是當一個事務在編輯這條信息的時候,禁止其他事務進行寫操作。
2.臟讀
一個用戶對一個資源做了修改,此時另外一個用戶正好讀取了這條被修改的記錄,然后,第一個用戶放棄修改,數據回到修改之前,這兩個不同的結果就是臟讀。(即B用戶讀取了一個A用戶沒有提交事務的數據(rollback transaction),這樣讀出來的數據是屬于臟數據)
下面是簡單的例子來實現臟讀:
首先T1為
begin tran
update Student set Age = 16 where Name = ‘小明’
waitfor delay '00:00:05' --延遲五秒
rollback tran --回滾事務
事務T2
select * from Student with(nolock) where Name = ‘小明’
-- 加 with(nolock)可以讀到未提交的數據,能提高查詢性能,但它并不是沒有缺點的,作為一個負面影響,nolock查詢還可能帶來讀取“幻影”數據或讀取在一個數據庫讀取事務中可以獲得的但在另一個事務中可能被滾回的數據的風險。
先執行T1,一兩秒之后執行T2,五秒之后再次執行T2,會發現中間有一個查詢結果小明年齡為16,后來因為事務回滾,造成查詢結果又變回為15,而年齡為16的這條數據就是臟數據。
3. 不可重復讀 :是指在一個事務內,多次讀同一數據。在這個事務還沒有結束時,另外一個事務也訪問該同一數據。那么,在第一個事務中的兩次讀數據之間,由于第二個事務的修改,那么第一個事務兩次讀到的的數據可能是不一樣的。這樣在一個事務內兩次讀到的數據是不一樣的,因此稱為是不可重復讀。
事務1第一次讀小明的年齡為15
事務2更新小明年齡為16
事務1第二次讀小明年齡為16
事務1的兩次查詢不一樣
解決辦法:如果只有在修改事務完全提交之后才可以讀取數據,則可以避免該問題
4. 幻讀 : 是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的數據進行了修改,這種修改涉及到表中的全部數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那么,以后就會發生操作第一個事務的用戶發現表中還有沒有修改的數據行,就好象發生了幻覺一樣。
事務1第一次查詢學生信息為兩條數據
事務2向學生表中插入一條新的信息
事務1第二次查詢學生信息是發現多了一條 產生幻讀
解決辦法:如果在操作事務完成數據處理之前,任何其他事務都不可以添加新數據,則可避免該問題
2. 隔離級別
●未授權讀取(讀未提交)(Read Uncommitted):允許臟讀取,但不允許更新丟失。如果一個事務已經開始寫數據,則另外一個數據則不允許同時進行寫操作,但允許其他事務讀此行數據。該隔離級別可以通過“排他寫鎖”實現。
●授權讀取(讀提交)(Read Committed):允許不可重復讀取,但不允許臟讀取。這可以通過“瞬間共享讀鎖”和“排他寫鎖”實現。讀取數據的事務允許其他事務繼續訪問該行數據,但是未提交的寫事務將會禁止其他事務訪問該行。
●可重復讀取(Repeatable Read):禁止不可重復讀取和臟讀取,但是有時可能出現幻影數據。這可以通過“共享讀鎖”和“排他寫鎖”實現。讀取數據的事務將會禁止寫事務(但允許讀事務),寫事務則禁止任何其他事務。
●序列化(Serializable):提供嚴格的事務隔離。它要求事務序列化執行,事務只能一個接著一個地執行,但不能并發執行。如果僅僅通過“行級鎖”是無法實現事務序列化的,必須通過其他機制保證新插入的數據不會被剛執行查詢操作的事務訪問到。
隔離級別越高,越能保證數據的完整性和一致性,但是對并發性能的影響也越大。對于多數應用程序,可以優先考慮把數據庫系統的隔離級別設為Read Committed,它能夠避免臟讀取,而且具有較好的并發性能。盡管它會導致不可重復讀、虛讀和第二類丟失更新這些并發問題,在可能出現這類問題的個別場合,可以由應用程序采用悲觀鎖或樂觀鎖來控制。
總結
- 上一篇: echarts的x轴数量固定_联轴器 多
- 下一篇: 完全理解icmp协议