用實(shí)例帶你了解 MySQL 全局鎖
本文轉(zhuǎn)載自微信公眾號「架構(gòu)精進(jìn)之路」,作者架構(gòu)精進(jìn)之路。轉(zhuǎn)載本文請聯(lián)系架構(gòu)精進(jìn)之路公眾號。
MySQL全局鎖會(huì)申請一個(gè)全局的讀鎖,對整個(gè)庫加鎖。
全局鎖的一般使用場景是:全局邏輯備份。
全局鎖的實(shí)現(xiàn)方式有兩種:
- //第一種方法
- Flush tables with read lock(FTWRL)
- //第二種方法
- set global readonly=true
當(dāng)數(shù)據(jù)庫處于全局鎖的狀態(tài)時(shí),其他線程的一下語句會(huì)被阻塞:數(shù)據(jù)更新語句(數(shù)據(jù)的增刪改)、數(shù)據(jù)定義語句(建表、索引變更、修改表結(jié)構(gòu)等)和更新類事務(wù)的提交語句。
釋放全局鎖
- unlock tables;
來個(gè)示例吧~
創(chuàng)建數(shù)據(jù)庫 `test`
- CREATE TABLE `test` (
- `name` varchar(32) NOT NULL DEFAULT '',
- `bid` int(10) unsigned NOT NULL DEFAULT '0'
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='測試';
插入數(shù)據(jù)
- insert into test values('A', 1), ('B',2),('C',3);
查看表數(shù)據(jù)
- > select * from test;
- +------+-----+
- | name | bid |
- +------+-----+
- | A | 1 |
- | B | 2 |
- | C | 3 |
- +------+-----+
加鎖
- flush tables with read lock;
新增數(shù)據(jù)
- insert into test values('D', 4);
執(zhí)行 insert 操作后,直接返回錯(cuò)誤結(jié)果:
- ERROR 1223 (HY000): Can't execute the query because you have a conflicting read lock
執(zhí)行查詢操作,可以正常返回結(jié)果:
- > select * from test;
- #返回結(jié)果:
- +------+-----+
- | name | bid |
- +------+-----+
- | A | 1 |
- | B | 2 |
- | C | 3 |
- +------+-----+
可以看到,當(dāng)我們加上全局鎖的時(shí)候,數(shù)據(jù)及表更新操作都沒辦法執(zhí)行,但表查詢不受影響。這樣會(huì)給我們的業(yè)務(wù)造成很大的影響(無法修改數(shù)據(jù)),索性 Innodb 引擎的可重復(fù)讀隔離級別可以讓我們不阻塞數(shù)據(jù)變更的同時(shí)導(dǎo)出數(shù)據(jù)。
官方自帶的邏輯備份工具是 mysqldump。當(dāng) mysqldump 使用參數(shù)–single-transaction 的時(shí)候,導(dǎo)數(shù)據(jù)之前就會(huì)啟動(dòng)一個(gè)事務(wù),來確保拿到一致性視圖。而由于 MVCC 的支持,這個(gè)過程中數(shù)據(jù)是可以正常更新的。
你一定在疑惑,有了這個(gè)功能,為什么還需要 FTWRL 呢?
一致性讀是好,但前提是引擎要支持這個(gè)隔離級別。
比如,對于 MyISAM 這種不支持事務(wù)的引擎,如果備份過程中有更新,總是只能取到最新的數(shù)據(jù),那么就破壞了備份的一致性。這時(shí),我們就需要使用 FTWRL 命令了。
single-transaction 方法只適用于所有的表使用事務(wù)引擎的庫。
如果有的表使用了不支持事務(wù)的引擎,那么備份就只能通過 FTWRL 方法。這往往是 DBA 要求業(yè)務(wù)開發(fā)人員使用 InnoDB 替代 MyISAM 的原因之一。
用 FTWRL 而不用 set global readonly = true
- 在有些系統(tǒng)中,readonly 的值會(huì)被用來做其他邏輯,比如用來判斷一個(gè)庫是主庫還是備庫。因此,修改 global 變量的方式影響面更大,我不建議你使用。
- 在異常處理機(jī)制上有差異。如果執(zhí)行 FTWRL 命令之后由于客戶端發(fā)生異常斷開,那么 MySQL 會(huì)自動(dòng)釋放這個(gè)全局鎖,整個(gè)庫回到可以正常更新的狀態(tài)。而將整個(gè)庫設(shè)置為 readonly 之后,如果客戶端發(fā)生異常,則數(shù)據(jù)庫就會(huì)一直保持 readonly 狀態(tài),這樣會(huì)導(dǎo)致整個(gè)庫長時(shí)間處于不可寫狀態(tài),風(fēng)險(xiǎn)較高。