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

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