例子補(bǔ)充:【數(shù)據(jù)庫】快速理解臟讀烟很、不可重復(fù)讀卿吐、幻讀
一 數(shù)據(jù)庫事務(wù)的隔離級別
數(shù)據(jù)庫事務(wù)的隔離級別有4個(gè)富弦,由低到高依次為Read uncommitted 灵嫌、Read committed 壹罚、Repeatable read 、Serializable 寿羞,這四個(gè)級別可以逐個(gè)解決臟讀 猖凛、不可重復(fù)讀 、幻讀這幾類問題绪穆。
1. Read UnCommitted(讀未提交)
最低的隔離級別辨泳。一個(gè)事務(wù)可以讀取另一個(gè)事務(wù)并未提交的更新結(jié)果。
2. Read Committed(讀提交)
大部分?jǐn)?shù)據(jù)庫采用的默認(rèn)隔離級別玖院。一個(gè)事務(wù)的更新操作結(jié)果只有在該事務(wù)提交之后菠红,另一個(gè)事務(wù)才可以的讀取到同一筆數(shù)據(jù)更新后的結(jié)果。
3. Repeatable Read(重復(fù)讀)
mysql的默認(rèn)級別难菌。整個(gè)事務(wù)過程中试溯,對同一筆數(shù)據(jù)的讀取結(jié)果是相同的,不管其他事務(wù)是否在對共享數(shù)據(jù)進(jìn)行更新郊酒,也不管更新提交與否遇绞。
4. Serializable(序列化)
最高隔離級別。所有事務(wù)操作依次順序執(zhí)行燎窘。注意這會(huì)導(dǎo)致并發(fā)度下降摹闽,性能最差。通常會(huì)用其他并發(fā)級別加上相應(yīng)的并發(fā)鎖機(jī)制來取代它褐健。
二 不同事務(wù)級別帶來的并發(fā)問題
1 臟讀
臟讀發(fā)生在一個(gè)事務(wù)A讀取了被另一個(gè)事務(wù)B修改钩骇,但是還未提交的數(shù)據(jù)。假如B回退,則事務(wù)A讀取的是無效的數(shù)據(jù)弥姻。這跟不可重復(fù)讀類似候址,但是第二個(gè)事務(wù)不需要執(zhí)行提交。
2 不可重復(fù)讀
在基于鎖的并行控制方法中纽匙,如果在執(zhí)行select時(shí)不添加讀鎖,就會(huì)發(fā)生不可重復(fù)讀問題拍谐。
在多版本并行控制機(jī)制中烛缔,當(dāng)一個(gè)遇到提交沖突的事務(wù)需要回退但卻被釋放時(shí)馏段,會(huì)發(fā)生不可重復(fù)讀問題。
在上面這個(gè)例子中践瓷,事務(wù)2提交成功院喜,它所做的修改已經(jīng)可見。然而晕翠,事務(wù)1已經(jīng)讀取了一個(gè)其它的值喷舀。在序列化和可重復(fù)讀的隔離級別中,數(shù)據(jù)庫管理系統(tǒng)會(huì)返回舊值淋肾,即在被事務(wù)2修改之前的值硫麻。在提交讀和未提交讀隔離級別下,可能會(huì)返回被更新的值樊卓,這就是“不可重復(fù)讀”拿愧。
有兩個(gè)策略可以防止這個(gè)問題的發(fā)生:
(1) 推遲事務(wù)2的執(zhí)行,直至事務(wù)1提交或者回退碌尔。這種策略在使用鎖時(shí)應(yīng)用浇辜。
(2) 而在多版本并行控制中,事務(wù)2可以被先提交唾戚。而事務(wù)1奢赂,繼續(xù)執(zhí)行在舊版本的數(shù)據(jù)上。當(dāng)事務(wù)1終于嘗試提交時(shí)颈走,數(shù)據(jù)庫會(huì)檢驗(yàn)它的結(jié)果是否和事務(wù)1膳灶、事務(wù)2順序執(zhí)行時(shí)一樣。如果是立由,則事務(wù)1提交成功轧钓。如果不是,事務(wù)1會(huì)被回退锐膜。
3 幻讀
幻讀發(fā)生在當(dāng)兩個(gè)完全相同的查詢執(zhí)行時(shí)毕箍,第二次查詢所返回的結(jié)果集跟第一個(gè)查詢不相同。
發(fā)生的情況:沒有范圍鎖道盏。
三 例子比較不可重復(fù)讀和幻讀
1 不可重復(fù)讀
不可重復(fù)讀的重點(diǎn)是修改: 同樣的條件, 你讀取過的數(shù)據(jù), 再次讀取出來發(fā)現(xiàn)值不一樣了
例子:
在事務(wù)1中而柑,Mary 讀取了自己的工資為1000,操作并沒有完成
con1 = getConnection();
select salary from employee empId ="Mary";
在事務(wù)2中,這時(shí)財(cái)務(wù)人員修改了Mary的工資為2000,并提交了事務(wù).
con2 = getConnection();
update employee set salary = 2000;
con2.commit();
在事務(wù)1中荷逞,Mary 再次讀取自己的工資時(shí)媒咳,工資變?yōu)榱?000
select salary from employee empId ="Mary";
在一個(gè)事務(wù)中前后兩次讀取的結(jié)果并不致,導(dǎo)致了不可重復(fù)讀种远。
2 幻讀
幻讀的重點(diǎn)在于新增或者刪除 (數(shù)據(jù)條數(shù)變化)涩澡。同樣的條件, 第1次和第2次讀出來的記錄數(shù)不一樣
例子:
目前工資為1000的員工有10人。
事務(wù)1,讀取所有工資為1000的員工坠敷。
con1 = getConnection();
Select * from employee where salary =1000;
共讀取10條記錄
這時(shí)另一個(gè)事務(wù)向employee表插入了一條員工記錄妙同,工資也為1000
con2 = getConnection();
Insert into employee(empId,salary) values("Lili",1000);
con2.commit();
事務(wù)1再次讀取所有工資為1000的員工
select * from employee where salary =1000;
共讀取到了11條記錄射富,這就像產(chǎn)生了幻讀。