Mysql鎖

mysql 鎖機(jī)制

標(biāo)簽(空格分隔): mysql


參考文檔

  1. https://www.2cto.com/database/201508/429967.html
  2. http://www.cnblogs.com/aipiaoborensheng/p/5767459.html

概念

  1. 共享鎖(S):允許一個(gè)事務(wù)去讀一行,阻止其他事務(wù)獲得相同的數(shù)據(jù)集的排他鎖。
  2. 排他鎖(X):允許獲得排他鎖的事務(wù)更新數(shù)據(jù),但是組織其他事務(wù)獲得相同數(shù)據(jù)集的共享鎖和排他鎖。
  3. 對(duì)于insert、update、delete,InnoDB會(huì)自動(dòng)給涉及的數(shù)據(jù)加排他鎖(X);對(duì)于一般的Select語(yǔ)句,InnoDB不會(huì)加任何鎖,事務(wù)可以通過(guò)以下語(yǔ)句給顯示加共享鎖或排他鎖。

共享鎖

select * from table_name where .....lock in share mode

Note left of 事務(wù)1: select * from table_1 where id=1 lock in share mode;
事務(wù)1-->事務(wù)2: 
Note right of 事務(wù)2: select * from table_1 where id=1 lock in share mode;
事務(wù)2-->事務(wù)1: 
Note left of 事務(wù)1: update table_1 set age=10 where id=1;
Note left of 事務(wù)1: 事務(wù)1更新時(shí)發(fā)現(xiàn)此行鎖被其他事務(wù)享用,等待
事務(wù)1-->事務(wù)2: 
Note right of 事務(wù)2: update table_1 set age=12 where id=1;
Note right of 事務(wù)2: 事務(wù)2更新時(shí)發(fā)現(xiàn)此行鎖被其他事務(wù)享用,也等待,導(dǎo)致死鎖

排他鎖

select * from table_name where .....for update

Note left of 事務(wù)1: select * from table_1 where id=1 for update;
事務(wù)1-->事務(wù)2: 
Note right of 事務(wù)2: select * from table_1 where id=1 for update;
Note right of 事務(wù)2: 等待...
事務(wù)2-->事務(wù)1: 
Note left of 事務(wù)1: update table_1 set age=10 where id=1;
Note left of 事務(wù)1: 更新完后釋放鎖
事務(wù)1-->事務(wù)2: 
Note right of 事務(wù)2: 獲得鎖后,得到其他事務(wù)提交的記錄

行鎖的三種形式

  1. Record lock:鎖定一條記錄。
  2. Gap lock
  3. Next-key lock

innoDB鎖問(wèn)題

事務(wù)(Transaction)及其ACID屬性

  • 原子性(Actomicity):事務(wù)是一個(gè)原子操作單元,其對(duì)數(shù)據(jù)的修改,要么全都執(zhí)行,要么全都不執(zhí)行。
  • 一致性(Consistent):在事務(wù)開(kāi)始和完成時(shí),數(shù)據(jù)都必須保持一致?tīng)顟B(tài)。這意味著所有相關(guān)的數(shù)據(jù)規(guī)則都必須應(yīng)用于事務(wù)的修改,以操持完整性;事務(wù)結(jié)束時(shí),所有的內(nèi)部數(shù)據(jù)結(jié)構(gòu)(如B樹(shù)索引或雙向鏈表)也都必須是正確的。
  • 隔離性(Isolation):數(shù)據(jù)庫(kù)系統(tǒng)提供一定的隔離機(jī)制,保證事務(wù)在不受外部并發(fā)操作影響的“獨(dú)立”環(huán)境執(zhí)行。這意味著事務(wù)處理過(guò)程中的中間狀態(tài)對(duì)外部是不可見(jiàn)的,反之亦然。
  • 持久性(Durable):事務(wù)完成之后,它對(duì)于數(shù)據(jù)的修改是永久性的,即使出現(xiàn)系統(tǒng)故障也能夠保持。

并發(fā)事務(wù)帶來(lái)的問(wèn)題

  • 更新丟失(Lost Update):當(dāng)兩個(gè)或多個(gè)事務(wù)選擇同一行,然后基于最初選定的值更新該行時(shí),由于每個(gè)事務(wù)都不知道其他事務(wù)的存在,就會(huì)發(fā)生丟失更新問(wèn)題——最后的更新覆蓋了其他事務(wù)所做的更新。例如,兩個(gè)編輯人員制作了同一文檔的電子副本。每個(gè)編輯人員獨(dú)立地更改其副本,然后保存更改后的副本,這樣就覆蓋了原始文檔。最后保存其更改保存其更改副本的編輯人員覆蓋另一個(gè)編輯人員所做的修改。如果在一個(gè)編輯人員完成并提交事務(wù)之前,另一個(gè)編輯人員不能訪問(wèn)同一文件,則可避免此問(wèn)題
  • 臟讀(Dirty Reads):一個(gè)事務(wù)正在對(duì)一條記錄做修改,在這個(gè)事務(wù)并提交前,這條記錄的數(shù)據(jù)就處于不一致?tīng)顟B(tài);這時(shí),另一個(gè)事務(wù)也來(lái)讀取同一條記錄,如果不加控制,第二個(gè)事務(wù)讀取了這些“臟”的數(shù)據(jù),并據(jù)此做進(jìn)一步的處理,就會(huì)產(chǎn)生未提交的數(shù)據(jù)依賴關(guān)系。這種現(xiàn)象被形象地叫做“臟讀”。
  • 不可重復(fù)讀(Non-Repeatable Reads):一個(gè)事務(wù)在讀取某些數(shù)據(jù)已經(jīng)發(fā)生了改變、或某些記錄已經(jīng)被刪除了!這種現(xiàn)象叫做“不可重復(fù)讀”。
  • 幻讀(Phantom Reads):一個(gè)事務(wù)按相同的查詢條件重新讀取以前檢索過(guò)的數(shù)據(jù),卻發(fā)現(xiàn)其他事務(wù)插入了滿足其查詢條件的新數(shù)據(jù),這種現(xiàn)象就稱為“幻讀”。

事務(wù)隔離級(jí)別

| 隔離級(jí)別 | 臟讀| 不可重復(fù)讀 | 幻讀 |
| -| - |
| 未提交讀(Read uncommitted) | √ | √ | √ |
| 已提交度(Read committed) | x | √ | √ |
| 可重復(fù)讀(Repeatable read) |x | x | √ |
| 可序列化(Serializable) | x | x | x |

mysql行鎖的特性

  1. innodb 的行鎖是在有索引的情況下,沒(méi)有索引的表是鎖定全表的.
    實(shí)例:
    id是主鍵
    | id| name|
    | -| - |
    | 1 | 1 |
    | 2 | 2 |
    | 3 | 3 |
    事務(wù)1update第一條id=1的數(shù)據(jù),事務(wù)不提交;事務(wù)2接著update第二條id=2的數(shù)據(jù)的時(shí)候等待,原因是id沒(méi)有加上索引,導(dǎo)致事務(wù)1鎖的是表鎖而不是行鎖。

  2. 如果是使用相同的索引鍵,會(huì)出現(xiàn)鎖沖突。
    示例:tab_with_index表中id字段有索引,name字段沒(méi)有索引。
    事務(wù)1:

select * from tab_with_index where id = 1 and name = '1' for update;

事務(wù)2:

select * from tab_with_index where id = 1 and name = '4' for update;

雖然事務(wù)2訪問(wèn)的是和事務(wù)1不同的記錄,但是因?yàn)槭褂昧讼嗤乃饕孕枰却i。

  1. 當(dāng)表有多個(gè)索引的時(shí)候,不同的事務(wù)可以使用不同的索引鎖定不同的行,另外,不論是使用主鍵索引、唯一索引或普通索引,InnoDB都會(huì)使用行鎖來(lái)對(duì)數(shù)據(jù)加鎖。
    示例:表tab_with_index的id字段有主鍵索引,name字段有普通索引。
    事務(wù)1:
select * from tab_with_index where id = 1 for update;

事務(wù)2:

select * from tab_with_index where name = '2' for update;

事務(wù)2使用name的索引訪問(wèn)記錄,因?yàn)橛涗洓](méi)有被索引,所以也可以獲得鎖。

間隙鎖(Next-Key鎖)

當(dāng) 我們用范圍條件而不是相等條件檢索數(shù)據(jù),并請(qǐng)求共享或排他鎖時(shí),InnoDB會(huì)給符合條件 的已有數(shù)據(jù)記錄的索引項(xiàng)加鎖;對(duì)于鍵值在條件范圍內(nèi)但并不存在的記錄,叫做“間隙(GAP)”,InnoDB也會(huì)對(duì)這個(gè)“間隙”加鎖,這種鎖機(jī)制就是所謂 的間隙鎖(Next-Key鎖)。
示例:

Select * from  emp where empid > 100 for update;

是一個(gè)范圍條件的檢索,InnoDB不僅會(huì)對(duì)符合條件的empid值為101的記錄加鎖,也會(huì)對(duì)empid大于101(這些記錄并不存在)的“間隙”加鎖。
InnoDB 使用間隙鎖的目的,一方面是為了防止幻讀,以滿足相關(guān)隔離級(jí)別的要求,對(duì)于上面的例子,要是不使用間隙鎖,如果其他事務(wù)插入了empid大于100的任何 記錄,那么本事務(wù)如果再次執(zhí)行上述語(yǔ)句,就會(huì)發(fā)生幻讀.
還要特別說(shuō)明的是,InnoDB除了通過(guò)范圍條件加鎖時(shí)使用間隙鎖外,如果使用相等條件請(qǐng)求給一個(gè)不存在的記錄加鎖,InnoDB也會(huì)使用間隙鎖!

一致性非鎖定讀

一致性非鎖定讀是指InnoDB存儲(chǔ)引擎通過(guò)多版本并發(fā)控制技術(shù)來(lái)讀取當(dāng)前數(shù)據(jù)庫(kù)的數(shù)據(jù)。如果當(dāng)前讀取的行正在執(zhí)行delete或者update操作,這時(shí)讀取操作不會(huì)等行鎖的釋放,而是去讀取行的快照數(shù)據(jù)。


非鎖定一致性讀.png

快照數(shù)據(jù)是指改行之前版本的數(shù)據(jù),該實(shí)現(xiàn)是通過(guò)undo段來(lái)實(shí)現(xiàn)的,而undo段用來(lái)在事務(wù)中保存回滾數(shù)據(jù),因此使用快照沒(méi)有增加額外的開(kāi)銷。
這是InnoDB存儲(chǔ)引擎的默認(rèn)讀取方式。

注意

  1. 不同的事務(wù)隔離級(jí)別下讀取的方式不同,并不是每個(gè)事務(wù)隔離級(jí)別下都是采用非鎖定的一致性讀。四種隔離級(jí)別中,READ COMMITTED和REPEATABLE READ這兩種隔離級(jí)別使用非鎖定的一致性讀。
  2. 不同的事務(wù)即使都使用非鎖定的一致性讀,但是對(duì)于快照數(shù)據(jù)的定義也各不相同。READ COMMITTED級(jí)別下非鎖定讀總是讀取鎖定行的最新一份快照數(shù)據(jù);而REPEATABLE READ級(jí)別下非鎖定讀總是讀取事務(wù)開(kāi)始時(shí)的數(shù)據(jù)版本。

例子

事務(wù)A 事務(wù)B
select * from table where id='1';
. update table set id =3 where id=1;
select * from table where id='1';
. commit;
select * from table where id='1';

上述例子中事務(wù)B update以后事務(wù)A第一次select的時(shí)候RC級(jí)別和RR級(jí)別獲取的結(jié)果都是id=1的那一條數(shù)據(jù);第二次select的時(shí)候,由于事務(wù)B已經(jīng)提交,RC級(jí)別select的結(jié)果就是id=3,而RR級(jí)別讀取的是事務(wù)開(kāi)始時(shí)的數(shù)據(jù),id=1。

一致性鎖定讀

默認(rèn)配置下事務(wù)的隔離級(jí)別為REPEATABLE READ,select操作為非一致性鎖定讀,但某些情況下需要對(duì)數(shù)據(jù)庫(kù)讀取操作進(jìn)行加鎖保證數(shù)據(jù)的一致性。select 有兩種一致的鎖定讀:

  • select ... for update
  • select ... lock in share mode

自增長(zhǎng)與鎖

InnoDB存儲(chǔ)引擎內(nèi)部對(duì)每個(gè)含有自增長(zhǎng)列的表有一個(gè)自增長(zhǎng)計(jì)數(shù)器,當(dāng)進(jìn)行insert操作時(shí),首先獲取計(jì)數(shù)器的最大值,加1后進(jìn)行insert操作。這個(gè)操作會(huì)加一個(gè)特殊的表鎖,AUTO-INC LOCK。這個(gè)鎖并不是在事務(wù)提交后才釋放,而是在insert語(yǔ)句執(zhí)行完后釋放。

缺點(diǎn)

雖然是insert后就釋放鎖,不是事務(wù)提交后才釋放,但是必須等前一個(gè)insert的完成才能進(jìn)行下一次insert,性能較差。

改進(jìn)

TODO...

外鍵與鎖

在對(duì)外鍵值進(jìn)行update和insert操作時(shí)首先需要查詢父表的記錄,即select父表,這個(gè)select操作不是使用一致性非鎖定讀,因?yàn)闀?huì)發(fā)生數(shù)據(jù)不一致的問(wèn)題,為此需要使用一致性鎖定讀,這時(shí)使用的select ... lock in share mode方式。當(dāng)父表對(duì)應(yīng)記錄加X(jué)鎖后,子表的操作將會(huì)阻塞。

例子

TODO...

鎖的算法

InnoDB存儲(chǔ)引擎有三種行鎖的算法

  • Record Lock:單行記錄上鎖
  • Gap Lock:間隙鎖,鎖定一個(gè)范圍
  • Next-Key Lock
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 當(dāng)一個(gè)系統(tǒng)訪問(wèn)量上來(lái)的時(shí)候,不只是數(shù)據(jù)庫(kù)性能瓶頸問(wèn)題了,數(shù)據(jù)庫(kù)數(shù)據(jù)安全也會(huì)浮現(xiàn),這時(shí)候合理使用數(shù)據(jù)庫(kù)鎖機(jī)制就顯得異...
    初來(lái)的雨天閱讀 3,611評(píng)論 0 22
  • MySQL的事務(wù)支持 MySQL的事務(wù)支持不是綁定在MySQL服務(wù)器本身,而是與存儲(chǔ)引擎相關(guān): MyISAM:不支...
    但莫閱讀 526評(píng)論 0 6
  • MySQL技術(shù)內(nèi)幕:InnoDB存儲(chǔ)引擎(第2版) 姜承堯 第1章 MySQL體系結(jié)構(gòu)和存儲(chǔ)引擎 >> 在上述例子...
    沉默劍士閱讀 7,468評(píng)論 0 16
  • MyISAM 和 MEMORY 存儲(chǔ)引擎采用的是表級(jí)鎖;InnoDB 存儲(chǔ)引擎即支持行級(jí)鎖,也支持表級(jí)鎖,但默認(rèn)情...
    微日月閱讀 913評(píng)論 0 0
  • 前言 數(shù)據(jù)庫(kù)鎖定機(jī)制是數(shù)據(jù)庫(kù)為了保證數(shù)據(jù)的一致性而使各種共享資源在并發(fā)訪問(wèn)時(shí)變的有序的一種規(guī)則。MySQL數(shù)據(jù)庫(kù)的...
    Justlearn閱讀 1,706評(píng)論 0 4