這篇文章能夠闡述清楚跟數(shù)據(jù)庫相關(guān)的四個概念:事務(wù)、數(shù)據(jù)庫讀現(xiàn)象禽作、隔離級別尸昧、鎖機制
一、事務(wù)
先來看下百度百科對數(shù)據(jù)庫事務(wù)的定義:
作為單個邏輯單元執(zhí)行一系列操作旷偿,要么完全執(zhí)行烹俗,要么完全不執(zhí)行。事務(wù)處理可以確保除非事務(wù)性單元內(nèi)的所有操作都成功完成萍程,否則不會永久更新面向數(shù)據(jù)的資源幢妄。
事務(wù)有四個屬性,稱為ACID屬性:
1茫负、原子性(Atomicity):事務(wù)是一個原子單位蕉鸳,要么全部執(zhí)行,要么全部不執(zhí)行忍法。
2潮尝、一致性(Consistent):事務(wù)的開始和結(jié)束榕吼,數(shù)據(jù)都必須保持一致狀態(tài)。
3衍锚、隔離性(isolation):數(shù)據(jù)庫系統(tǒng)提供隔離機制友题,保證并發(fā)事務(wù)之間是互相不干擾的。也就意味著事務(wù)處理過程中的中間狀態(tài)對其他的事務(wù)是透明的戴质。
4度宦、持久性(Durable):事務(wù)完成之后,對數(shù)據(jù)的修改是永久性的告匠,即使出現(xiàn)系統(tǒng)故障也能夠保持戈抄。
事務(wù)是一系列SQL語句的集合,如果沒有事務(wù)后专,會出現(xiàn)什么問題划鸽?或者說SQL只能一條一條的單個執(zhí)行,會出現(xiàn)什么問題戚哎?
這個很簡單裸诽,如果沒有事務(wù),我們平時生活中的銀行轉(zhuǎn)賬就無法操作型凳。
二丈冬、數(shù)據(jù)庫讀現(xiàn)象
ACID屬性里面有一個是隔離級別,即并發(fā)事務(wù)之間互相不干擾甘畅」∪铮互相不干擾只是一個終極狀態(tài),且需要消耗巨大的性能疏唾。在我們實際應(yīng)用過程中蓄氧,是存在很大的灰度空間的:隔離級別有程度的區(qū)分。所以如果隔離程度控制的比較弱的話槐脏,就會產(chǎn)生臟讀喉童、不可重復(fù)讀以及幻讀的現(xiàn)象。
1准给、臟讀
事務(wù)T1修改某個字段的值泄朴,然后事務(wù)T2讀取該值,此后T1撤銷了對該字段的更新露氮,或者更新成另外的值才commit到數(shù)據(jù)庫中祖灰,這樣T2讀取的數(shù)據(jù)是無效的或者錯誤的。導(dǎo)致T2依據(jù)臟數(shù)據(jù)所做的操作也是錯誤的畔规。
思聰同學(xué)中午去食堂吃飯局扶,看到窗邊的座位被如花同學(xué)占有了,思聰認為這個座位已經(jīng)被占有了,就轉(zhuǎn)身去找其他的座位三妈。不料畜埋,如花同學(xué)起身離開了。事實是:如花并不是吃飯畴蒲,而是臨時坐在那里等她的約會對象悠鞍,只是臨時小坐一會,并沒有真正“commit”模燥。
2咖祭、不可重復(fù)讀
在數(shù)據(jù)庫訪問中,一個事務(wù)范圍內(nèi)的兩次相同的查詢卻返回了不同的數(shù)據(jù)蔫骂。
事務(wù)T1讀取某一數(shù)據(jù)么翰,事務(wù)T2讀取并修改了該數(shù)據(jù),T1為了對讀取值進行驗證而重新讀取辽旋,卻發(fā)現(xiàn)得到了不同的結(jié)果浩嫌。
思聰同學(xué)中午去食堂吃飯,看到窗邊的座位是空的补胚,便屁顛屁顛的跑去打飯码耐,回來后卻發(fā)現(xiàn)這個座位被如花同學(xué)搶去了。
3溶其、幻讀
幻讀解決了不可重復(fù)讀的問題伐坏,即在同一個事務(wù)范圍內(nèi),兩次相同的查詢結(jié)果是相同的握联。但是可以新增表中的數(shù)據(jù)記錄。
幻讀是指事務(wù)T1對表中的數(shù)據(jù)進行修改每瞒,假設(shè)修改涉及了表中全部的數(shù)據(jù)行金闽,同時第二個事務(wù)也修改這個表中的數(shù)據(jù),這種修改是向表中插入一條新的數(shù)據(jù)剿骨。后面就會出現(xiàn)操作了T1事務(wù)的用戶發(fā)現(xiàn)表中還有沒有修改的數(shù)據(jù)行代芜,仿佛出現(xiàn)了幻覺一樣。
思聰同學(xué)中午去食堂吃飯浓利,看到窗邊的座位是空的挤庇,便屁顛屁顛的跑去打飯,回來后窗邊的座位還是空的贷掖,便很高興坐上去準(zhǔn)備開始吃飯嫡秕,這時候卻發(fā)現(xiàn)如花同學(xué)搬了一個小板凳坐在旁邊狼吞虎咽,思聰頓時沒有了胃口苹威。
如果需要解決臟讀昆咽、不可重復(fù)讀、幻讀等這些數(shù)據(jù)庫讀現(xiàn)象,就必須相應(yīng)提高事務(wù)的隔離級別掷酗。但是數(shù)據(jù)庫的隔離級別越高调违,對應(yīng)的并發(fā)能力就越弱,性能也就相應(yīng)的越差泻轰,所以我們還需根據(jù)具體的應(yīng)用場景去權(quán)衡技肩。
三、事務(wù)隔離級別
1浮声、未提交讀
事務(wù)的最低隔離級別虚婿,在這種隔離級別下,一個事務(wù)可以讀取另外一個事務(wù)未提交的數(shù)據(jù)阿蝶。
數(shù)據(jù)庫鎖實現(xiàn)原理:
事務(wù)T在讀數(shù)據(jù)的時候并未對數(shù)據(jù)進行加鎖雳锋,事務(wù)T在修改數(shù)據(jù)的時候?qū)?shù)據(jù)增加行級共享鎖
T1在讀取數(shù)據(jù)時,T2可以對相同數(shù)據(jù)進行讀取羡洁、修改玷过。因為T1沒有進行任何鎖操作;當(dāng)T2對記錄進行修改時筑煮,T1再次讀取數(shù)據(jù)可以讀取到T2修改后的數(shù)據(jù)辛蚊。因為T2對數(shù)據(jù)進行修改只增加了行級共享鎖,T1可以再增加共享讀鎖進行數(shù)據(jù)讀日嬷佟(盡管T2沒有提交事務(wù))
如上所述袋马,這種隔離級別,會導(dǎo)致臟讀現(xiàn)象
2秸应、已提交讀
在一個事務(wù)修改數(shù)據(jù)過程中虑凛,如果事務(wù)沒有進行提交,其他事務(wù)不能讀取該數(shù)據(jù)
數(shù)據(jù)庫鎖實現(xiàn)原理:
事務(wù)T在讀取數(shù)據(jù)時增加行級共享鎖软啼,讀取一旦結(jié)束桑谍,立即釋放;事務(wù)T在修改數(shù)據(jù)時增加行級排他鎖祸挪,直到事務(wù)結(jié)束才釋放锣披。
T1在讀取數(shù)據(jù)的過程中,T2也可以對相同數(shù)據(jù)進行讀取贿条,但是不能進行修改(T1增加的是共享鎖雹仿,T2也可以增加共享鎖,但是不能增加排他鎖)整以。T1讀取結(jié)束后胧辽,會立即釋放共享鎖,這時T2可以增加排他鎖悄蕾,對數(shù)據(jù)進行修改票顾,而此時T1既不能對數(shù)據(jù)進行讀取也不能進行修改础浮,直到T2事務(wù)結(jié)束。
如上所述奠骄,這種隔離級別豆同,解決了臟讀問題,但是不能解決不可重復(fù)讀現(xiàn)象含鳞。
3影锈、可重復(fù)讀
事務(wù)T在數(shù)據(jù)讀取時,必須增加行級共享鎖蝉绷,直到事務(wù)結(jié)束鸭廷;事務(wù)T在修改數(shù)據(jù)過程中,必須增加行級排他鎖熔吗,直到數(shù)據(jù)結(jié)束辆床。
數(shù)據(jù)庫鎖實現(xiàn)原理:
T1在讀取數(shù)據(jù)的過程中,T2也可以對相同數(shù)據(jù)進行讀取桅狠,但是不能進行修改(T1增加的是共享鎖讼载,T2也可以增加共享鎖,但是不能增加排他鎖)中跌。直到T1事務(wù)結(jié)束后咨堤,才會釋放共享鎖,這時T2才可以增加排他鎖漩符,對數(shù)據(jù)進行修改一喘。
如上所述,這種隔離級別嗜暴,解決了不可重復(fù)讀現(xiàn)象凸克,但是這種隔離級別解決不了幻讀的問題:
T1進行查詢,讀取了10條記錄闷沥,并對十條記錄增加了行級鎖触徐,此時T2是無法對這10行數(shù)據(jù)進行修改操作的,但是由于沒有表級鎖狐赡,它可以增加一條滿足T1查詢條件的記錄。隨后T1在進行查詢時疟丙,會發(fā)現(xiàn)雖然10條記錄沒有改變颖侄,但是突然多了一條記錄。
4享郊、序列化
產(chǎn)生幻讀是由于沒有進行范圍查詢時沒有增加范圍鎖览祖。
數(shù)據(jù)庫鎖實現(xiàn)原理:
** 事務(wù)T在讀取數(shù)據(jù)時,必須先增加表級共享鎖炊琉,直到事務(wù)結(jié)束才釋放展蒂;事務(wù)T在修改數(shù)據(jù)時又活,必須先增加表級排他鎖,直到事務(wù)結(jié)束才釋放锰悼。**
T1在讀取A表時柳骄,增加了表級共享鎖,此時T2也可以讀取A表箕般,但是不能進行任何數(shù)據(jù)的修改耐薯,直到T1事務(wù)結(jié)束。隨后T2可以增加對A表的表級排他鎖丝里,此時T1不能讀取A表中的任何數(shù)據(jù)曲初,更不能進行修改。
如上所述杯聚,可序列化解決了臟讀臼婆、不可重復(fù)讀、幻讀等讀現(xiàn)象幌绍,但是隔離級別越來越高的同時颁褂,在并發(fā)性上也就越來越低。
**四纷捞、事務(wù)操作實踐 **
默認情況下痢虹,MYSQL是自動提交的,也就意味著平時我們執(zhí)行一條update語句時主儡,MYSQL是自動幫我們提交的奖唯,盡快我們沒有顯示執(zhí)行commit命令。但是這種只適用于單條SQL的執(zhí)行糜值。
如果我們想要同時執(zhí)行多條SQL丰捷,并且執(zhí)行過程中有SQL執(zhí)行異常,需要回滾前面已經(jīng)成功執(zhí)行的SQL或者最終想回滾全部寂汇,則必須顯示的使用事務(wù)病往。
開始一項事務(wù):start tr ansaction或者begin;
提交事務(wù):commit骄瓣;
回滾事務(wù):rollback停巷;
事務(wù)提交之后的操作:chain;
事務(wù)回滾之后的操作:release榕栏;
修改當(dāng)前連接的提交方式:set autocommit畔勤;如果設(shè)置了set autocommit=0,則設(shè)置之后所有的事務(wù)都需要顯式的通過命令來進行提交或者回滾扒磁。
查詢當(dāng)前會話的事務(wù)隔離級別
查詢當(dāng)前系統(tǒng)的事務(wù)隔離級別
修改當(dāng)前會話的事務(wù)隔離級別
提交讀演示
客戶端A 開啟事務(wù)庆揪,并更新數(shù)據(jù)
此時事務(wù)還沒有提交,開啟客戶端B妨托,并進行查詢缸榛,此時的數(shù)據(jù)還是未更新前的
客戶端A進行事務(wù)提交吝羞,然后客戶端B查詢,此時是最新的數(shù)據(jù)
commit and chain的演示
如果在提交的時候使用commit and chain内颗,那么在提交后立即開始一個新的事務(wù)
A提交事務(wù)后钧排,B再進行查詢
開啟事務(wù)會隱式解鎖
鎖表期間,用start transaction 命令開始一個新事務(wù)起暮,則會隱式的執(zhí)行unlock tables
A對表進行寫鎖操作
此時B進行查詢:由于被A鎖表辱士,所以查詢被阻塞
A開啟一個事務(wù)
由于A開啟事務(wù)正塌,隱式的釋放了寫鎖半等,所以B的查詢不再被阻塞
SAVEPOINT的使用
事務(wù)中可以通過定義SAVEPOINT缩滨,指定回滾事務(wù)的一個部分
A開啟事務(wù)并insert一條記錄,并設(shè)置savepoint
B進行查詢纸厉,查詢到的是開啟事務(wù)前的數(shù)據(jù)
A又插入一條數(shù)據(jù)系吭,然后回滾到savepoint
B進行查詢
作者:冬瓜蔡原文:http://www.cnblogs.com/dongguacai/p/7114885.html