mysql鎖機制深層而又復雜,而且針對不對的存儲引擎鎖實現(xiàn)的方式以及表現(xiàn)形式又不一樣陈惰,本文只針對mysql?InnoDB行鎖實現(xiàn)方式 進行整理本文純屬掃盲級別,大神請忽略··
先說一些數(shù)據(jù)庫事務的背景知識:
事務的ACID原則:
事務是由一組SQL語句組成的邏輯處理單元,事務具有以下4個屬性官份,通常簡稱為事務的ACID屬性缴罗。
? ? ? ?原子性(Atomicity):事務是一個原子操作單元助琐,其對數(shù)據(jù)的修改,要么全都執(zhí)行瞒爬,要么全都不執(zhí)行弓柱。
? ? 一致性(Consistent):在事務開始和完成時,數(shù)據(jù)都必須保持一致狀態(tài)侧但。這意味著所有相關的數(shù)據(jù)規(guī)則都必須應用于事務的修改矢空,以保持數(shù)據(jù)的完整性;事務結束時禀横,所有的內部數(shù)據(jù)結構(如B樹索引或雙向鏈表)也都必須是正確的屁药。
? ? ? ? 隔離性(Isolation):數(shù)據(jù)庫系統(tǒng)提供一定的隔離機制,保證事務在不受外部并發(fā)操作影響的“獨立”環(huán)境執(zhí)行柏锄。這意味著事務處理過程中的中間狀態(tài)對外部是不可見的酿箭,反之亦然。 ? ? ? ? 持久性(Durable):事務完成之后趾娃,它對于數(shù)據(jù)的修改是永久性的缭嫡,即使出現(xiàn)系統(tǒng)故障也能夠保持。
銀行轉帳就是事務的一個典型例子
2.并發(fā)事務處理帶來的問題
相對于串行處理來說抬闷,并發(fā)事務處理能大大增加數(shù)據(jù)庫資源的利用率妇蛀,提高數(shù)據(jù)庫系統(tǒng)的事務吞吐量,從而可以支持更多的用戶笤成。但并發(fā)事務處理也會帶來一些問題评架,主要包括以下幾種情況。
l? 更新丟失(Lost Update):當兩個或多個事務選擇同一行炕泳,然后基于最初選定的值更新該行時纵诞,由于每個事務都不知道其他事務的存在,就會發(fā)生丟失更新問題--最后的更新覆蓋了由其他事務所做的更新培遵。例如浙芙,兩個編輯人員制作了同一文檔的電子副本登刺。每個編輯人員獨立地更改其副本,然后保存更改后的副本茁裙,這樣就覆蓋了原始文檔塘砸。最后保存其更改副本的編輯人員覆蓋另一個編輯人員所做的更改。如果在一個編輯人員完成并提交事務之前晤锥,另一個編輯人員不能訪問同一文件掉蔬,則可避免此問題。
l? 臟讀(Dirty Reads):一個事務正在對一條記錄做修改矾瘾,在這個事務完成并提交前女轿,這條記錄的數(shù)據(jù)就處于不一致狀態(tài);這時壕翩,另一個事務也來讀取同一條記錄蛉迹,如果不加控制,第二個事務讀取了這些“臟”數(shù)據(jù)放妈,并據(jù)此做進一步的處理北救,就會產(chǎn)生未提交的數(shù)據(jù)依賴關系。這種現(xiàn)象被形象地叫做"臟讀"芜抒。
l? 不可重復讀(Non-Repeatable Reads):一個事務在讀取某些數(shù)據(jù)后的某個時間珍策,再次讀取以前讀過的數(shù)據(jù),卻發(fā)現(xiàn)其讀出的數(shù)據(jù)已經(jīng)發(fā)生了改變宅倒、或某些記錄已經(jīng)被刪除了攘宙!這種現(xiàn)象就叫做“不可重復讀”。
l? 幻讀(Phantom Reads):一個事務按相同的查詢條件重新讀取以前檢索過的數(shù)據(jù)拐迁,卻發(fā)現(xiàn)其他事務插入了滿足其查詢條件的新數(shù)據(jù)蹭劈,這種現(xiàn)象就稱為“幻讀”。
3.事務隔離級別
在上面講到的并發(fā)事務處理帶來的問題中线召,“更新丟失”通常是應該完全避免的铺韧。但防止更新丟失,并不能單靠數(shù)據(jù)庫事務控制器來解決缓淹,需要應用程序對要更新的數(shù)據(jù)加必要的鎖來解決祟蚀,因此,防止更新丟失應該是應用的責任割卖。
“臟讀”、“不可重復讀”和“幻讀”患雏,其實都是數(shù)據(jù)庫讀一致性問題鹏溯,必須由數(shù)據(jù)庫提供一定的事務隔離機制來解決。數(shù)據(jù)庫實現(xiàn)事務隔離的方式淹仑,基本上可分為以下兩種丙挽。
l? 一種是在讀取數(shù)據(jù)前肺孵,對其加鎖,阻止其他事務對數(shù)據(jù)進行修改颜阐。
l? 另一種是不用加任何鎖平窘,通過一定機制生成一個數(shù)據(jù)請求時間點的一致性數(shù)據(jù)快照(Snapshot),并用這個快照來提供一定級別(語句級或事務級)的一致性讀取凳怨。從用戶的角度來看瑰艘,好像是數(shù)據(jù)庫可以提供同一數(shù)據(jù)的多個版本,因此肤舞,這種技術叫做數(shù)據(jù)多版本并發(fā)控制(MultiVersion Concurrency Control紫新,簡稱MVCC或MCC),也經(jīng)常稱為多版本數(shù)據(jù)庫李剖。
數(shù)據(jù)庫的事務隔離越嚴格芒率,并發(fā)副作用越小,但付出的代價也就越大篙顺,因為事務隔離實質上就是使事務在一定程度上 “串行化”進行偶芍,這顯然與“并發(fā)”是矛盾的。同時德玫,不同的應用對讀一致性和事務隔離程度的要求也是不同的匪蟀,比如許多應用對“不可重復讀”和“幻讀”并不敏感,可能更關心數(shù)據(jù)并發(fā)訪問的能力化焕。
讀數(shù)據(jù)一致性及允許的并發(fā)副作用
InnoDB的行鎖模式及加鎖方法
InnoDB實現(xiàn)了以下兩種類型的行鎖萄窜。
l? 共享鎖(S):允許一個事務去讀一行,阻止其他事務獲得相同數(shù)據(jù)集的排他鎖撒桨。
l? 排他鎖(X):允許獲得排他鎖的事務更新數(shù)據(jù)查刻,阻止其他事務取得相同數(shù)據(jù)集的共享讀鎖和排他寫鎖
對于UPDATE、DELETE和INSERT語句凤类,InnoDB會自動給涉及數(shù)據(jù)集加排他鎖(X)穗泵;對于普通SELECT語句,InnoDB不會加任何鎖谜疤;事務可以通過以下語句顯示給記錄集加共享鎖或排他鎖佃延。
?? 共享鎖(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。
?? 排他鎖(X):SELECT * FROM table_name WHERE ... FOR UPDATE夷磕。
注意:如果SELECT語句使用了共享鎖 在當前事務下在使用排它鎖 在并發(fā)場景下會很容易出現(xiàn)死鎖
解決辦法:對于鎖定行記錄后需要進行更新操作的應用履肃,應該使用SELECT... FOR UPDATE方式獲得排他鎖。(記鬃:特別重要3咂濉!C圊巍1烀3筛!!荆残!在項目中遇到過的E!D谒埂蕴潦!)
InnoDB行鎖實現(xiàn)方式
InnoDB行鎖是通過給索引上的索引項加鎖來實現(xiàn)的,這一點MySQL與Oracle不同嘿期,后者是通過在數(shù)據(jù)塊中對相應數(shù)據(jù)行加鎖來實現(xiàn)的品擎。InnoDB這種行鎖實現(xiàn)特點意味著:只有通過索引條件檢索數(shù)據(jù),InnoDB才使用行級鎖备徐,否則萄传,InnoDB將使用表鎖!(記酌刍:特別重要P懔狻!2渌Q芰狻!<缁怼脊串!)
在實際應用中,要特別注意InnoDB行鎖的這一特性清钥,不然的話琼锋,可能導致大量的鎖沖突,從而影響并發(fā)性能(記姿钫选:特別重要B瓶病!4畚颉C仗尽!0嵩帷荷腊!)