幻读和不可重复读
MySQL
MySQL默認(rèn)的隔離級(jí)別為RR,因此只會(huì)出現(xiàn)幻讀的情況。
不會(huì)出現(xiàn)不可重復(fù)讀的問(wèn)題。
幻讀
事務(wù)在插入已經(jīng)檢查過(guò)不存在的記錄時(shí),驚奇的發(fā)現(xiàn)這些數(shù)據(jù)已經(jīng)存在了,之前的檢測(cè)獲取到的數(shù)據(jù)如同鬼影一般。
例子:
在事務(wù)1中,查詢(xún)User表id為100的是用戶(hù)否存在,如果不存在則插入一條id為100的數(shù)據(jù)。
select?*?from?User?where?id?=?100;在事務(wù)1查詢(xún)結(jié)束后,事務(wù)2往User表中插入了一條id為100的數(shù)據(jù)。
insert?into?`User`(`id`,?`name`)?values?(100,?'Josh');??此時(shí),由于事務(wù)1查詢(xún)到id為1的用戶(hù)不存在,因此插入1條id為1的數(shù)據(jù)。
insert?into?`?User`(`id`,?`name`)?values?(100,?'China');但是由于事務(wù)2已經(jīng)插入了1條id為100的數(shù)據(jù),因此此時(shí)會(huì)報(bào)主鍵沖突。
對(duì)于事務(wù)1 的業(yè)務(wù)來(lái)說(shuō)是執(zhí)行失敗的,這里事務(wù)1 就是發(fā)生了幻讀,因?yàn)槭聞?wù)1讀取的數(shù)據(jù)狀態(tài)并不能支持他的下一步的業(yè)務(wù),出現(xiàn)了幻覺(jué)。
這里要靈活的理解讀取的意思,第一次select是讀取,第二次的insert其實(shí)是先讀取再插入,只不過(guò)是在MySQL的機(jī)制中讀取的,插入數(shù)據(jù)也是要先讀取一下有沒(méi)有主鍵沖突才能決定是否執(zhí)行插入。
?
Oracle
Oracle默認(rèn)的隔離級(jí)別為Rc,因此可能出現(xiàn)不可重復(fù)度和幻讀。
不可重復(fù)讀
同樣的條件,你讀取過(guò)的數(shù)據(jù),再次讀取出來(lái)發(fā)現(xiàn)值不一樣了。
例子:
在事務(wù)1中,smith讀取了自己的工資為18000,但是此時(shí)事務(wù)1的操作還并沒(méi)有完成 ,后面還有1次相同的讀取操作。
con1?=?getConnection(); select?salary?from?employee?where?employeeName?="smith";??在事務(wù)2中,這時(shí)財(cái)務(wù)人員修改了smith的工資為28000,并提交了事務(wù)。
con2?=?getConnection();???? update?employee?set?salary?=?2000?where?employeeName?=?"smith";???? con2.commit();在事務(wù)1中,smith再次讀取自己的工資時(shí),工資變?yōu)榱?8000 。
//con1?? select?salary?from?employee?where?employeeName?="smith";在一個(gè)事務(wù)中前后兩次讀取的結(jié)果并不致,導(dǎo)致了不可重復(fù)讀。
幻讀
同樣的條件,第1次和第2次讀出來(lái)的記錄數(shù)不一樣。
具體的說(shuō):在同一個(gè)事務(wù)中,在不同的時(shí)刻t1和t2,對(duì)某一范圍的數(shù)據(jù)讀取時(shí),結(jié)果不一樣。
例子:
目前工資為10000的員工有10人。?
事務(wù)1,讀取所有工資為1000的員工,共讀取10條記錄 。
con1?=?getConnection();???? Select?*?from?employee?where?salary?=10000;這時(shí)另一個(gè)事務(wù)向employee表插入了一條員工記錄,工資也為10000?
con2?=?getConnection();???? Insert?into?employee(employeeName,salary)?values("zhangsan",10000);???? con2.commit();事務(wù)1再次讀取所有工資為1000的員工,共讀取到了11條記錄,這就產(chǎn)生了幻讀。?
//con1 select?*?from?employee?where?salary?=10000;臟讀:(同時(shí)操作都沒(méi)提交的讀取)
臟讀又稱(chēng)無(wú)效數(shù)據(jù)讀出。一個(gè)事務(wù)讀取另外一個(gè)事務(wù)還沒(méi)有提交的數(shù)據(jù)叫臟讀。
例如:事務(wù)T1修改了一行數(shù)據(jù),但是還沒(méi)有提交,這時(shí)候事務(wù)T2讀取了被事務(wù)T1修改后的數(shù)據(jù),之后事務(wù)T1因?yàn)槟撤N原因Rollback了,那么事務(wù)T2讀取的數(shù)據(jù)就是臟的。
解決辦法:把數(shù)據(jù)庫(kù)的事務(wù)隔離級(jí)別調(diào)整到READ_COMMITTED
不可重復(fù)讀:(同時(shí)操作,事務(wù)一分別讀取事務(wù)二操作時(shí)和提交后的數(shù)據(jù),讀取的記錄內(nèi)容不一致)
不可重復(fù)讀是指在同一個(gè)事務(wù)內(nèi),兩個(gè)相同的查詢(xún)返回了不同的結(jié)果。
例如:事務(wù)T1讀取某一數(shù)據(jù),事務(wù)T2讀取并修改了該數(shù)據(jù),T1為了對(duì)讀取值進(jìn)行檢驗(yàn)而再次讀取該數(shù)據(jù),便得到了不同的結(jié)果。
解決辦法:把數(shù)據(jù)庫(kù)的事務(wù)隔離級(jí)別調(diào)整到REPEATABLE_READ
幻讀:(和可重復(fù)讀類(lèi)似,但是事務(wù)二的數(shù)據(jù)操作僅僅是插入和刪除,不是修改數(shù)據(jù),讀取的記錄數(shù)量前后不一致)
例如:系統(tǒng)管理員A將數(shù)據(jù)庫(kù)中所有學(xué)生的成績(jī)從具體分?jǐn)?shù)改為ABCDE等級(jí),但是系統(tǒng)管理員B就在這個(gè)時(shí)候插入(注意時(shí)插入或者刪除,不是修改))了一條具體分?jǐn)?shù)的記錄,當(dāng)系統(tǒng)管理員A改結(jié)束后發(fā)現(xiàn)還有一條記錄沒(méi)有改過(guò)來(lái),就好像發(fā)生了幻覺(jué)一樣。這就叫幻讀。
解決辦法:把數(shù)據(jù)庫(kù)的事務(wù)隔離級(jí)別調(diào)整到SERIALIZABLE_READ
總結(jié)
- 上一篇: 字符串2在字符串1中第一次出现的位置st
- 下一篇: c++ primer第5版中文版.pdf