為了模擬并發(fā)環(huán)境,SQL SERVER中打開兩個查詢窗口(分別表示事務1、事務2)即可,并發(fā)用戶用事務1,事務2簡稱
測試表腳本:
CREATE TABLE [Customer](
??????? [CustID] [int] NOT NULL,
??????? [Fname] [nvarchar](20),
??????? [Lname] [nvarchar](20),
??????? [Address] [nvarchar](50),
??????? [City] [nvarchar](20),
??????? [State] [nchar](2) DEFAULT ('CA'),
??????? [Zip] [nchar](5) NOT NULL,
??????? [Phone] [nchar](10)
)
insert into customer values(1, 'Gary', 'Mckee', '111 Main', 'Palm Springs', 'CA', 94312, 7605551212)
insert into customer values(2, 'Tom', 'Smith', '609 Geogia', 'Fresno' 'JP', 33045, 5105551212)
insert into customer values(3, 'Jams', 'bond', 'ST Geogie 21', 'Washington', 'NY', 20331, 4405551864)
sqlserver事務隔離級別的測試:
1、read uncommitted:可以讀取其他事務未提交的數(shù)據(jù)
打開事務1,運行:
begin tran
select * from customer
??????? update customer set state = 'TN' where CustID = 3
轉到事務2,運行:
set transaction isolation level read uncommitted
begin tran
select * from customer
此時看到的數(shù)據(jù)是事務1已經(jīng)更新但還未提交的(3號記錄state值TN)
2、read committed:只能讀取其他事務已經(jīng)提交的數(shù)據(jù)(有進行修改的)
打開事務1,運行:
begin tran
select * from customer
??????? update customer set state = 'TN' where CustID = 3
轉到事務2,運行:
set transaction isolation level read committed
begin tran
select * from customer
此時會發(fā)現(xiàn)事務2一直等待,并不結束
3、repeatable read:保證使用該隔離級別的事務,在讀取數(shù)據(jù)時的數(shù)據(jù)保持一致,不會被別的事務修改、刪除數(shù)據(jù)(因為別的事務如果有修改、刪除操作會被阻塞)
開始事務1,修改事務級別為可重復讀,執(zhí)行:
set transaction isolation level repeatable read
begin tran
select * from customer where State = 'CA'
得到1條記錄,這個時候事務2中運行:
set transaction isolation level repeatable read
begin tran
update Customer set state = 'JP' where state = 'CA'
commit
會發(fā)現(xiàn)事務2一直等待,并不結束。返回事務1,運行:
select * from customer where State = 'CA'??????????????? --2次讀取結果一致
commit
事務1成功結束后,再返回事務2,發(fā)現(xiàn)事務2也完成了。通過鎖機制阻塞其它事務的修改,保持了事務期間讀取的一致性
4、serializable:使用該隔離級別的事務用到的表將全部鎖定,其他事務不可以進行添加、修改、刪除
開始事務1,修改事務級別為序列化級別,執(zhí)行:
set transaction isolation level serializable
begin tran
select * from customer
開始事務2,執(zhí)行:
begin tran
update Customer set state = 'JP' where state = 'CA'
會發(fā)現(xiàn)事務2一直等待
5、snapshot:快照隔離
注意:要向使用快照隔離必須先設置當前數(shù)據(jù)庫能進行快照隔離
如:
ALTER DATABASE NetBarDB
SET ALLOW_SNAPSHOT_ISOLATION ON
在SNAPSHOT隔離下運行的事務將讀取數(shù)據(jù),
然后由另一事務修改此數(shù)據(jù)。SNAPSHOT事務不阻塞由其他事務執(zhí)行的更新操作,
它忽略數(shù)據(jù)的修改繼續(xù)從版本化的行讀取數(shù)據(jù)。
開始事務1,修改事務級別為快照級別,執(zhí)行:
set transaction isolation level snapshot
begin tran
select * from customer
開始事務2,執(zhí)行:
begin tran
update customer set state = 'TN' where CustID = 3
發(fā)現(xiàn)有一行被修改
回到事務1,執(zhí)行
select * from customer
發(fā)現(xiàn)查詢出來的CustID = 3的state仍然是'NY'并不是'TN'
sqlserver事務常見的情況:
1、丟失更新
Sqlserver默認隔離級別是提交讀(read committed),在該級別下,可能會有丟失更新的問題。
SQL SERVER
打開事務1運行:
set transaction isolation level read committed
begin tran
select * from customer??????????????? --看到3條記錄
現(xiàn)在切換到事務2,此時事務1還未結束。在事務2中運行:
set transaction isolation level read committed
begin tran
select * from customer??????????????? --看到3條記錄,和事務1中相同
現(xiàn)在假設事務1事務繼續(xù)運行,修改數(shù)據(jù)并提交:
update customer set state = 'TK' where CustID = 3
commit
回到事務2,事務2根據(jù)先前查詢到的結果修改數(shù)據(jù):
update customer set Zip = 99999 where state = 'NY'
commit
結果因為事務1已經(jīng)修改了事務2的where條件數(shù)據(jù),事務2未成功修改數(shù)據(jù)(其實準確的說應該算是幻象讀引起的更新失敗。不過若滿足條件的記錄數(shù)多的話,事務2的update可能更新比預期的數(shù)量少的記錄數(shù),也可算“丟失”了部分本應完成的更新。個人認為只要明白實際上發(fā)生了什么即可,不必過分追究字眼)。丟失更新還可能有別的情形,比如事務2也是
update customer set state = 'KO' where CustID = 3
兩個事務都結束后,事務2的結果反映到數(shù)據(jù)庫中,但事務1的更新丟失了,事務2也不知道自己覆蓋了事務1的更新。
2、臟讀演示
sqlserver的默認隔離級別是提交讀(read committed)
打開事務1,運行:
begin tran
select * from customer
??????? update customer set state = 'TN' where CustID = 3
轉到事務2,運行:
set transaction isolation level read uncommitted
begin tran
select * from customer
此時看到的數(shù)據(jù)是事務1已經(jīng)更新但還未提交的(3號記錄state值TN)。而如果事務1發(fā)覺數(shù)據(jù)處理有誤,轉到事務1,進行回滾:
??????? Rollback
此時事務2如根據(jù)剛讀取的數(shù)據(jù)進一步處理,會造成錯誤。它讀取的數(shù)據(jù)并未更新到數(shù)據(jù)庫,是“臟”的
3、不可重復讀
Sql server的默認級別沒有臟讀問題,但存在不可重復讀問題。
打開事務1,運行:
set transaction isolation level read committed
begin tran
select * from customer where State = 'CA'
可以得到1條記錄,這個時候事務2中運行:
set transaction isolation level read committed
begin tran
update Customer set state = 'JP' where state = 'CA'
commit
事務2插入一條記錄并提交。回到事務1,事務1繼續(xù)運行,此時它再次相同的查詢,并借此作進一步修改,卻發(fā)現(xiàn)讀取到的數(shù)據(jù)發(fā)生了變化。
select * from customer where State = 'CA'
--2次讀取不一致,之后的數(shù)據(jù)處理應該取消。否則不正確
update Customer set city = 'garden' where state = 'CA'
commit
讀取未能獲得記錄。也就是說在同一事務中兩次相同的查詢獲得了不同的結果,產(chǎn)生讀取不可重復現(xiàn)象
4、幻像讀
當sqlserver的隔離級別設置為可重復讀(repeatable read),可以解決上面例子出現(xiàn)的問題。其內(nèi)部是通過事務期間保持讀鎖來實現(xiàn)的。
開始事務1,修改事務級別為可重復讀,執(zhí)行:
set transaction isolation level repeatable read
begin tran
select * from customer where State = 'CA'
和上例一樣得到1條記錄,這個時候事務2中運行:
set transaction isolation level repeatable read
begin tran
update Customer set state = 'JP' where state = 'CA'
commit
會發(fā)現(xiàn)事務2一直等待,并不結束。返回事務1,運行:
select * from customer where State = 'CA'??????????????? --2次讀取結果一致
update Customer set city = 'garden' where state = 'CA'
commit
事務2成功結束后,再返回事務1,發(fā)現(xiàn)事務1也完成了。通過鎖機制阻塞其它事務的修改,保持了事務期間讀取的一致性。然而,如果是插入數(shù)據(jù),則還是會出現(xiàn)問題:
開始事務1,修改事務級別為可重復讀,執(zhí)行:
set transaction isolation level repeatable read
begin tran
select * from customer where State = 'CA'
得到1條記錄,這個時候事務2中運行:
set transaction isolation level repeatable read
begin tran
insert into customer values(4, 'hellow', 'world', 'paradise 001', 'garden', 'CA', 00000, 1119995555)
commit
發(fā)現(xiàn)事務2立刻提交并正常結束了。返回事務1,運行:
select * from customer where State = 'CA'
會發(fā)現(xiàn)得到了2條記錄。這種現(xiàn)象就叫做幻像讀。
更多文章、技術交流、商務合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
