????????根據(jù)加鎖的范圍,MySQL里面的鎖大致可以分成全局鎖、表級鎖和行鎖三類。
? ? ? ? 全局鎖就是對整個數(shù)據(jù)庫實例加鎖。MySQL提供了一個加全局鎖的方法,命令是Flush tables with read lock(FTWRL)。當(dāng)你需要讓整個庫處于只讀狀態(tài)的時候,可以使用這個命令,之后其他線程的以下語句會被阻塞:數(shù)據(jù)更新語句、數(shù)據(jù)定義語句和更新事務(wù)的提交語句。全局鎖的典型使用場景是做全庫邏輯備份,也就是把整庫每個表都select出來存成文本。
? ? ? ? 表級別的鎖有兩種:一種是表鎖,一種是元數(shù)據(jù)鎖。
? ? ? ? 表鎖的語法是lock tables... read/write。與FTWRL類似,可以用unlock tables主動釋放鎖,也可以在客戶端斷開的時候自動釋放。需要注意,lock tables語法除了會限制別的線程讀寫外,也限定了本縣城接下來的操作對象。
? ? ? ? 元數(shù)據(jù)鎖是MDL,不需要顯式使用,在訪問一個表的時候會被自動動加上。MDL的作用是,保證讀寫的正確性。當(dāng)一個表做增刪改查操作的時候,加MDL讀鎖;當(dāng)要對表結(jié)構(gòu)變更操作的時候,加MDL寫鎖。讀鎖之間不互斥,因此你可以有多個線程同時對一張表增刪改查。讀寫鎖之間、寫鎖之間是互斥的,用來保證變更結(jié)構(gòu)操作的安全性。因此,如果有兩個線程要同時給一個表加字段,其中一個要等另一個執(zhí)行完才能開始執(zhí)行。
? ? ? ? 雖然MDL鎖是系統(tǒng)默認(rèn)會加的,但卻是你不能忽略的一個機制。比如下面這個例子,經(jīng)常有人掉到這個坑里:給一個小表價格字段,導(dǎo)致整個庫掛了。
? ? ? ? 那么如何安全地給小表加字段?首先我們要解決長事務(wù),事務(wù)不提交,就會一直占著MDL鎖。在MySQL的information_schema庫的innodb_trx表中,你可以查到當(dāng)前執(zhí)行中的事務(wù)。如果你要做DDL變更的表剛好有長事務(wù)在執(zhí)行,要考慮先暫停DDL,或者kill掉這個長事務(wù)。但有時候kill未必管用,因為新的請求馬上就來了。比較理想的機制是,在alter table語句里面設(shè)定等待時間,如果在這個指定的等待時間里面能夠拿到MDL寫鎖最好,拿不到也不要阻塞后面的業(yè)務(wù)語句,先放棄。之后開發(fā)人員或者DBA再通過重試命令重復(fù)這個過程。