MySQL鎖管理(并發(fā)鎖,行鎖,表鎖,預(yù)加鎖,全局鎖等等)

  1. MySQL中并發(fā)和隔離控制機制

    Meta-data元數(shù)據(jù)鎖:在table cache緩存里實現(xiàn)的,為DDL(Data Definition Language)提供隔離操作。一種特別的meta-data元數(shù)據(jù)類型,叫Name Lock。(SQL層)
    表級table-level數(shù)據(jù)鎖(SQL層)
    存儲引擎特有機制 ― row locks行鎖,page locks頁鎖,table locks表級,版本控制(在引擎中實現(xiàn))
    全局讀鎖 ― FLUSH TABLES WITH READ LOCK(SQL層)

2.在語句執(zhí)行中表的生命周期

DML(Data Manipulation Language):

計算語句使用到的所有表
在每個表:打開open表 ― 從table cache緩存里得到TABLE對象,并在此表加上meta-data元數(shù)據(jù)鎖
等待全局讀鎖后改變數(shù)據(jù)
在每個表:鎖lock表 ― 在表加上table-level數(shù)據(jù)鎖
執(zhí)行語句:調(diào)用:handler::write_row()/read_rnd()/read_index(),等;隱式地調(diào)用引擎級engine-level鎖機制
在每個表:釋放表的數(shù)據(jù)鎖
在每個表:釋放表的DDL鎖并把表放回table cache緩存里
DDL語句也是一樣,沒有典型的執(zhí)行計劃。

3.獲取meta-data元數(shù)據(jù)鎖

meta-data元數(shù)據(jù)鎖的實現(xiàn)作為TABLE對象的一個屬性,TABLE對象代表了table cache緩存。
meta-data元數(shù)據(jù)鎖為如下任何一種:
shared共享鎖 ― 隱式地加鎖,只通過標(biāo)記TABLE對象“被使用”;
semi-exclusive半獨享鎖,也叫Name Lock,RENAME操作會在源表和目標(biāo)加上此鎖;
exclusive獨享,也叫exclusive name lock,CREATE TABLE … SELECT操作會在目標(biāo)表上加上此鎖,如果沒有的話。

4.表緩存(table cache)

是一個HASH變量,叫open_cache
TABLE對象是HASH元素
以HASH的操作被LOCK_open mutex互斥量保護

4.1內(nèi)部結(jié)構(gòu)(The table cache: internal structure)

在緩存里,每個物理表可能被多個TABLE實例表示
相同表的所有TABLE實例,通過相連的列(a linked list)連接著
每個TABLE實例有一個table cache緩存版本的復(fù)制 ― TABLE實例保存的版本不會和當(dāng)前table cache緩存版本一致,而是保存舊的和從緩存刪除的
被某些語句使用的TABLE實例被會標(biāo)記為對其它的語句來說是無效的 ― 這就是meta-data元數(shù)據(jù)鎖的本質(zhì)
在緩存中的TABLE實例通常地有一個有效的句柄實例連接著它

4.2內(nèi)部運算(The table cache: operations)

主要的代碼在:sql/sql_base.cc,sql/lock.cc,sql/table.h,sql/sql_table.cc
主要的方法:open_table(),close_thread_tables(),close_cached_table(),lock_table_names()
事實上,一個概念/對象組合不僅用于緩存或鎖定:LOCK_open mutex互斥量也用到其它的操作,如:使磁盤上和處理中的表創(chuàng)建的原子性
典型的操作,來自隔離等級Pov的重要(注:isolation PoV沒研究出是什么意思):語句查詢時,打開和關(guān)閉表 ― shared共享鎖;強制和等待直到表的所有實例被關(guān)閉 ― exclusive獨享(但不完全);Name Lock ― 特殊地情況,當(dāng)手上沒有TABLE實例,只能使用一個特殊的占位符(甚至表可能不存在)。

4.4鎖多表(The table cache: locking multiple tables)

使用一種嘗試和回退(try and back-off)的技術(shù)來避免死鎖(樂觀鎖)
為了DDL操作的一套訣竅,如使鎖升級或者防止DDL失效
LOCK_open問題
Lock_open互斥量:
保護table cache緩存內(nèi)的結(jié)構(gòu)
分組存儲引擎內(nèi)的表和對象的.frm文件的創(chuàng)建,也為RENAME操作提供原子性操作
在每個語句訪問表時會使用它兩次:在open_tables()和close_thread_tables()
在使用DDL操作時,磁盤讀寫和甚至同步(sync)都會使用它

5.ALTER TABLE例子

ALTER TABLE執(zhí)行的簡化計劃:

以TL_WRITE_ALLOW_READ的打開和加鎖表(新版 InnoDB Plugin已改為:TL-READ-NO-INSERT)
創(chuàng)建一個以臨時名字的被ALTER的復(fù)制表
強制并等待直到表的所有實例都關(guān)閉(鎖升級)
交換新和舊的版本

6.RENAME TABLE例子

得到源表和目的表的name-lock鎖:在table cache緩存內(nèi)插入特殊的TABLE實例的占位符并等待直到這些表的所有實例都關(guān)閉
重命名這些表的.frm文件和調(diào)用handler::rename_table()方法
刪除name-lock鎖

7.表級table-level鎖

主要源代碼見:sql/lock.cc,mysys/thr_lock.cc。mysql_lock/unlock_tables()(SQL層操作)和thr_multi_lock()/thr_lock()(鎖兼容邏輯lock-compatibility logic)
表是以打開著被加鎖的。被加鎖的對象被句柄關(guān)聯(lián)著;存儲引擎會調(diào)整鎖的類型。如innodb/bdb,事實上大量的對象被加鎖的,如merge/partition,見handler::store_lock()方法。
使用鎖等級避免死鎖。所有表一次性加鎖;如果存儲引擎調(diào)整鎖造成死鎖,由存儲引擎負責(zé)
在一些情況下,表會更早地被解鎖

8 .預(yù)加鎖(pre-locking)

歷史上避免死鎖方案用于表級table-level數(shù)據(jù)鎖,是要求一次性加鎖一個語句內(nèi)的所有表
因此,對語句使用的函數(shù)/觸發(fā),我們不得不打開所有直接地或間接地用到的表,且對它們加鎖。為這個,我們建立一個被使用表的可傳送閉包
為了有效實現(xiàn),我們混合層次和訪問(layers and access)成某些解析/語句上下文(parser/statement context),這些上下文來自主要處理表的模板

9.全局讀鎖(global read lock)

實現(xiàn)為FLUSH TABLES WITH READ LOCK,用來備份
從執(zhí)行上防止DDL和DML
建議:每個DDL/DML語句檢查是否有一個正掛著的全局讀鎖和停止是否有任何一個。
通過直接調(diào)用wait_if_global_read_lock()(在這個情況我們會設(shè)置來自全局讀鎖的保護,且只有調(diào)用start_waiting_global_read_lock()來消除這個保護,通常在這情況下沒有打開的表);
或者通過mysql_lock_tables()(在后一種情況下,我們還重新打開表)
線程操作FLUSH TABLES WITH READ LOCK來設(shè)置一個全局讀鎖的標(biāo)識,初始一個FLUSH TABLES語句,然后等待直到所有的表緩存都清空
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容