繼續(xù)上篇博客 事務(wù)特性及隔離問題铁瞒。
我們來做一個(gè)關(guān)于隔離級(jí)別的實(shí)驗(yàn)荞估,將演示各個(gè)級(jí)別導(dǎo)致的隔離問題。
我們先打開兩個(gè)MySQL窗口衅斩,來模擬并發(fā)操作。
- 臟讀
只有Read uncommitted級(jí)別才會(huì)發(fā)生臟讀問題怠褐,所以將其中一個(gè)窗口的隔離級(jí)別設(shè)置為Read uncommitted畏梆。輸入set transaction isolation level Read uncommitted;
在MySQL5.5的64位版本中輸入該段代碼是無法修改隔離級(jí)別的,應(yīng)該輸入set session transaction isolation level read committed;
修改隔離級(jí)別后奈懒,該窗口就被允許發(fā)生臟讀〉煊浚現(xiàn)在給這兩個(gè)窗口命名一下,方便后續(xù)講解磷杏,我們就令設(shè)置了事務(wù)隔離級(jí)別的窗口為B溜畅,另一個(gè)窗口為A。
在A极祸、B窗口分別開啟一個(gè)事務(wù)慈格,輸入start transaction;
現(xiàn)在同時(shí)查看兩個(gè)用戶的表數(shù)據(jù)
在這里插入圖片描述
現(xiàn)在在A窗口完成轉(zhuǎn)賬操作,輸入
update account set money = money - 200 where name = 'aaa';
update account set money = money + 200 where name = 'bbb';
然后查詢表數(shù)據(jù)
轉(zhuǎn)賬操作成功執(zhí)行贿肩。
此時(shí)在B窗口進(jìn)行查詢
會(huì)發(fā)現(xiàn),B窗口讀取到了A窗口未提交的數(shù)據(jù)汰规,此時(shí)在A窗口進(jìn)行回滾操作汤功,再次查詢表數(shù)據(jù)
兩個(gè)用戶的表數(shù)據(jù)都回到了原來的狀態(tài),但是B窗口在之前查詢數(shù)據(jù)的時(shí)候溜哮,是確認(rèn)了aaa賬戶轉(zhuǎn)賬了200元給bbb賬戶的滔金,而此時(shí)轉(zhuǎn)賬操作卻被回滾了,錢又相當(dāng)于轉(zhuǎn)回給了aaa賬戶茂嗓,此時(shí)就造成了bbb賬戶的經(jīng)濟(jì)損失餐茵,這就是臟讀現(xiàn)象。
- 不可重復(fù)讀
修改事務(wù)隔離級(jí)別述吸,在B窗口輸入set transaction isolation level Read committed;
這次我們重復(fù)剛才的操作忿族,兩邊同時(shí)開啟事務(wù),然后在A窗口更新數(shù)據(jù)蝌矛,接著兩邊都查詢一下表數(shù)據(jù)
在這里插入圖片描述
此時(shí)會(huì)發(fā)現(xiàn)道批,在A窗口未提交之前,B窗口的數(shù)據(jù)不會(huì)改變入撒。這時(shí)候就避免了臟讀隆豹,但是它會(huì)導(dǎo)致不可重復(fù)讀。我們讓A窗口提交茅逮,然后再次到B窗口查詢
在這里插入圖片描述
此時(shí)B窗口的表數(shù)據(jù)發(fā)生了變化璃赡,讀取到了A窗口提交的結(jié)果判哥,需要注意的是,B窗口在同一個(gè)事務(wù)中卻讀取到了兩次不同的表數(shù)據(jù)碉考,這就是不可重復(fù)讀塌计。 - 虛讀
修改事務(wù)隔離級(jí)別,在B窗口輸入set transaction isolation level Repeatable read;
在A豆励、B窗口分別開啟一個(gè)事務(wù)夺荒,在A窗口轉(zhuǎn)賬提交,B窗口連續(xù)地查詢良蒸,會(huì)發(fā)現(xiàn)B窗口是不會(huì)讀取到A提交的結(jié)果的技扼,這樣就避免了不可重復(fù)讀。
在A窗口輸入更新語句
update account set money = money-500 where name = 'bbb';
update account set money = money+500 where name = 'ccc';
然后提交A窗口的操作嫩痰,查詢兩邊的表數(shù)據(jù)
發(fā)現(xiàn)即使A窗口提交了操作剿吻,B窗口的表數(shù)據(jù)仍然不會(huì)被改變,證實(shí)了剛才的結(jié)論串纺,但是該隔離級(jí)別會(huì)導(dǎo)致虛讀的產(chǎn)生丽旅。很遺憾的是,虛讀無法為大家舉例了纺棺,因?yàn)樘撟x發(fā)生的概率是非常低的榄笙,但是方法還是給大家介紹一下。
在A窗口插入一條數(shù)據(jù)祷蝌,輸入
insert into account values (4,'ddd',1000);
茅撞,然后在B窗口進(jìn)行表數(shù)據(jù)查詢,如果查詢到了A窗口插入的數(shù)據(jù)巨朦,說明發(fā)生了虛讀米丘,但很顯然,這個(gè)現(xiàn)象并沒有發(fā)生糊啡,所以圖我就不貼了拄查。
- 最后介紹一下最后一個(gè)事務(wù)隔離級(jí)別
演示一下Serializable的串行處理效果。
將B窗口的級(jí)別設(shè)置為Serializable棚蓄,然后在A堕扶、B窗口同時(shí)開啟一個(gè)事務(wù),此時(shí)在B窗口執(zhí)行查詢語句梭依,然后在A窗口插入或更新一條數(shù)據(jù)挣柬,輸入insert into account values(5,'eee',1000);
當(dāng)你按回車鍵執(zhí)行語句時(shí),你會(huì)發(fā)現(xiàn)睛挚,A窗口并沒有馬上執(zhí)行sql語句,而是阻塞了急黎。那這是為什么呢扎狱?因?yàn)樵摷?jí)別是最高隔離級(jí)別侧到,采取串行處理方法,在一個(gè)用戶操作該數(shù)據(jù)庫時(shí)淤击,不允許別的用戶操作匠抗。
那么接下來請(qǐng)注意了,在JDBC程序中如何控制數(shù)據(jù)庫的隔離級(jí)別呢污抬?
在Connection接口中定義了五個(gè)字段汞贸,它們就是用來控制對(duì)應(yīng)的隔離級(jí)別的,只需要調(diào)用setTransactionIsolation(int level)
方法并將對(duì)應(yīng)的字段傳入印机,即可達(dá)到控制隔離級(jí)別的效果矢腻。如果不設(shè)置隔離級(jí)別,將采用數(shù)據(jù)庫默認(rèn)級(jí)別射赛,Oracle和MySQL數(shù)據(jù)庫的默認(rèn)級(jí)別是什么還記得嗎多柑?不記得的話就再次閱讀一下我的上一篇博客。
還有一個(gè)需要注意的地方楣责,在MySQL5.5的64位版本中竣灌,輸入set transaction isolation level
代碼并不能成功修改事務(wù)隔離級(jí)別,這又是為什么呢秆麸?因?yàn)樵贛ySQL5.0的規(guī)范中就規(guī)定初嘹,該條語句必須加上一個(gè)關(guān)鍵字session
,也就是說沮趣,想要成功修改屯烦,你得輸入set session transaction isolation level
才能成功修改。