(2)解鎖階段
當事務釋放了乙個封鎖以後,事務進入解鎖階段,在該階段只能進行解鎖操作不能再進行加鎖操作。
5、隱式和顯示鎖定
innodb會根據隔離級別在需要的時候自動加鎖,這稱為隱式加鎖。另外,innodb也支援通過特定的語句進行顯示加鎖
顯示加共享鎖:
select .... lock in share mode
顯示加排它鎖
select .... for update
二、多版本併發控制(mvcc)
mysql的大多數事務型儲存引擎實現的都不是簡單的行鎖。基於提公升併發效能的考慮,一般都實現了多版本併發控制(mvcc)。可以認為,mvcc是行鎖的乙個變種,但它在很多情況下避免了加鎖操作,減少了開銷。mvcc實現了非阻塞的讀操作,寫操作也只鎖定必要的行。
1、mvcc的實現方式
不同的儲存引擎的mvcc實現是不同的,典型的有悲觀併發控制和樂觀併發控制。
(1)悲觀併發控制
正如其名,它指的是對資料被外界(包括本系統當前的其他事務,以及來自外部系統的事務處理)修改持保守態度,因此,在整個資料處理過程中,將資料處於鎖定狀態。悲觀鎖的實現,往往依靠資料庫提供的鎖機制實現。在悲觀鎖的情況下,為了保證事務的隔離性,就需要一致性鎖定讀。讀取資料時給加鎖,其它事務無法修改這些資料。修改刪除資料時也要加鎖,其它事務無法讀取這些資料。
(2)樂觀併發控制
相對悲觀併發控制而言,樂觀併發控制採取了更加寬鬆的加鎖機制。悲觀併發控制大多數情況下依靠資料庫的鎖機制實現,以保證操作最大程度的獨占性。但隨之而來的就是資料庫效能的大量開銷,特別是對長事務而言,這樣的開銷往往無法承受。而樂觀併發控制在一定程度上解決了這個問題。樂觀併發控制,大多是基於資料版本( version )記錄機制實現。何謂資料版本?即為資料增加乙個版本標識,在基於資料庫表的版本解決方案中,一般是通過為資料庫表增加乙個 「version」 欄位來實現。讀取出資料時,將此版本號一同讀出,之後更新時,對此版本號加1。此時,將提交資料的版本資料與資料庫表對應記錄的當前版本資訊進行比對,如果提交的資料版本號大於資料庫表當前版本號,則予以更新,否則認為是過期資料。
2、innodb中mvcc的實現
在innodb中,使用樂觀併發控制來實現mvcc。在每行資料後新增兩個額外的隱藏的值來實現mvcc,這兩個值乙個記錄這行資料何時被建立,另外乙個記錄這行資料何時過期(或者被刪除)。 在實際操作中,儲存的並不是時間,而是事務的版本號,每開啟乙個新事務,事務的版本號就會遞增。
(1)mvcc的具體操作
在可重複讀事務隔離(rr)級別下,mvcc的具體操作如下:
select語句
innodb會根據以下兩個條件檢查每行記錄:
(a)建立版本號<=當前事務版本號
這樣可以確保事務讀取的行,要麼在事務開始前已經存在,要麼是事務自身插入或者修改過的。
(b)刪除版本號為空,或者,刪除版本號》當前事務版本號
這樣可以確保事務讀取到的行在事務開始之前未被刪除。
insert語句
儲存當前事務版本號為行的建立版本號。
delete語句
儲存當前事務版本號為行的刪除版本號。
update語句
插入一條新紀錄,儲存當前事務版本號為行建立版本號,同時儲存當前事務版本號到原來刪除的行。
通過mvcc,雖然每行記錄都需要額外的儲存空間,更多的行檢查工作以及一些額外的維護工作,但可以減少鎖的使用,大多數讀操作都不用加鎖,讀資料操作很簡單,效能很好,並且也能保證只會讀取到符合標準的行,也只鎖住必要行。
(2)快照讀與當前讀
在rr隔離級別中,通過mvcc機制,雖然讓資料變得可重複讀,但我們讀到的資料可能是歷史資料!這在一些對於資料的時效特別敏感的業務中,就很可能出問題。
對於這種讀取歷史資料的方式,我們叫它快照讀( snapshot read),而讀取資料庫當前版本資料的方式,叫當前讀 (current read)。很顯然,在mvcc中:
快照讀:普通的select語句。如下所示:
select * from table ....;
當前讀:特殊的讀操作,插入、更新、刪除操作,都屬於當前讀,處理的都是當前的資料,需要加鎖。具體如下所示:
select * from table where .... lock in share mode;
select * from table where .... for update;
insert ....;
update ....;
delete ....;
事務的隔離級別實際上都是定義了當前讀的級別,mysql為了減少鎖處理(包括等待其它鎖)的時間,提公升併發能力,引入了快照讀的概念,使得select不用加鎖。而update、insert這些「當前讀」就需要另外的模組來解決了。
為了解決「當前讀」中的幻讀問題,mysql事務使用了next-key鎖。
(3)next-key鎖
next-key鎖是行鎖和間隙鎖的合併,行鎖上文已經介紹了,接下來說下間隙鎖。
間隙鎖鎖加在不存在的空閒空間,可以是兩個索引記錄之間,也可能是第乙個索引記錄之前或最後乙個索引之後的空間。
next-key鎖是行鎖與間隙鎖的組合,這樣,當innodb掃瞄索引記錄的時候,會首先對選中的索引記錄加上行鎖,再對索引記錄兩邊的間隙(向左掃瞄掃到第乙個比給定引數小的值, 向右掃瞄掃瞄到第乙個比給定引數大的值, 然後以此為界,構建乙個區間)加上間隙鎖。如果乙個間隙被事務t1加了鎖,其它事務是不能在這個間隙插入記錄的。這樣就防止了幻讀,如下演示所示:
時間賬戶更新事務a
賬戶新增事務b
t1開始事務
t2開始事務
t3把所有賬戶的餘額清0(獲取行鎖和間隙鎖)
t4插入乙個新賬戶,設定餘額為100
(獲取不到鎖,等待)
t5等待
t6提交事務,釋放鎖
等待t8
獲取鎖,插入成功
t9提交事務,釋放鎖
mysql隱式鎖 innodB的隱式鎖
一 知識準備之隱式鎖 innodb 實現了乙個延遲加鎖的機制,來減少加鎖的數量,在 中稱為隱式鎖 implicit lock 隱式鎖中有個重要的元素,事務id trx id 隱式鎖的邏輯過程如下 a.innodb的每條記錄中都乙個隱含的trx id欄位,這個字段存在於簇索引的b tree中。b.在操...
Java類鎖 物件鎖 私有鎖 隱式鎖
類鎖和物件鎖是否會衝突?物件鎖和私有鎖是否會衝突?通過例項來進行說明。一 相關約定 為了明確後文的描述,先對本文涉及到的鎖的相關定義作如下約定 1.類鎖 在 中的方法上加了static和synchronized的鎖,或者synchronized class 的 段,如下文中的increament 2...
隱式鎖與顯式鎖詳細對比
synchronized修飾的物件,該物件就是隱式鎖,例子如下 public static void main string args static class ticket implements runnable catch interruptedexception e count system....