創(chuàng)新互聯(lián)建站專業(yè)為企業(yè)提供尚志網(wǎng)站建設(shè)、尚志做網(wǎng)站、尚志網(wǎng)站設(shè)計(jì)、尚志網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)與制作、尚志企業(yè)網(wǎng)站模板建站服務(wù),十多年尚志做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。
鎖是計(jì)算機(jī)協(xié)調(diào)多個(gè)進(jìn)程或純線程并發(fā)訪問(wèn)某一資源的機(jī)制。
在數(shù)據(jù)庫(kù)中,除傳統(tǒng)的計(jì)算資源(CPU、RAM、I/O)的爭(zhēng)用以外,數(shù)據(jù)也是一種供許多用戶共享的資源。
如何保證數(shù)據(jù)并發(fā)訪問(wèn)的一致性、有效性是所在有數(shù)據(jù)庫(kù)必須解決的一個(gè)問(wèn)題,鎖沖突也是影響數(shù)據(jù)庫(kù)并發(fā)訪問(wèn)性能的一個(gè)重要因素。從這個(gè)角度來(lái)說(shuō),鎖對(duì)數(shù)據(jù)庫(kù)而言顯得尤其重要,也更加復(fù)雜。
使用數(shù)據(jù)庫(kù),避免不了并發(fā)問(wèn)題,當(dāng)并發(fā)事務(wù)同時(shí)訪問(wèn)一個(gè)資源時(shí),有可能導(dǎo)致數(shù)據(jù)不一致,因此需要一種機(jī)制來(lái)將數(shù)據(jù)訪問(wèn)順序化,以保證數(shù)據(jù)庫(kù)數(shù)據(jù)的一致性。
鎖就是其中的一種機(jī)制。
我們可以用公廁做個(gè)比喻。
公廁是可供多個(gè)消費(fèi)者使用的,因此可能出現(xiàn)多個(gè)人同時(shí)需要使用廁所的情況。
但是,廁所只有一個(gè),總不能大家一起吧?
為了避免沖突,于是廁所里裝了鎖,某一個(gè)人在上測(cè)試時(shí),可以在里面用鎖鎖住,其他人就不能再?gòu)耐饷娲蜷_了,只能等待。
等里面的人出來(lái)了,從里面把鎖打開,外面的人才能進(jìn)去。
下面,帶你一起梳理下 MySQL 的鎖管理機(jī)制和鎖的執(zhí)行流程,先有一個(gè)大致的脈絡(luò)。
1、全局讀鎖 — FLUSH TABLES WITH READ LOCK(SQL層)
2、表級(jí) table-level 數(shù)據(jù)鎖(SQL層)
3、Meta-data 元數(shù)據(jù)鎖:在 table cache 緩存里實(shí)現(xiàn)的,為 DDL(Data Definition Language)提供隔離操作。
4、存儲(chǔ)引擎特有機(jī)制 — row locks行鎖,page locks頁(yè)鎖,table locks表級(jí),版本控制(在引擎中實(shí)現(xiàn))
相對(duì)其他數(shù)據(jù)庫(kù)而言,MySQL 的鎖機(jī)制比較簡(jiǎn)單,其最顯著的特點(diǎn)是不同的存儲(chǔ)引擎支持不同的鎖機(jī)制。
1、計(jì)算語(yǔ)句使用到的所有表;
2、在每個(gè)表:打開表,從 table cache 緩存里得到 TABLE 對(duì)象,并在此表加上 meta-data 元數(shù)據(jù)鎖;
3、等待全局讀鎖后改變數(shù)據(jù);
4、在每個(gè)表:鎖表,在表加上 table-level 數(shù)據(jù)鎖;
5、執(zhí)行語(yǔ)句:調(diào)用:handler::write_row()/read_rnd()/read_index() 等;隱式地調(diào)用引擎級(jí) engine-level 鎖機(jī)制;
6、在每個(gè)表:釋放表的數(shù)據(jù)鎖;
7、在每個(gè)表:釋放表的 DDL 鎖并把表放回 table cache 緩存里;
下面,我們開始簡(jiǎn)單針對(duì)每一種鎖,看下都有什么特點(diǎn)。
加了全局鎖后,整個(gè)庫(kù)變?yōu)橹蛔x狀態(tài),所有的寫操作都會(huì)被阻塞,包括:
數(shù)據(jù)的增刪改
表結(jié)構(gòu)的創(chuàng)建、修改
更新事務(wù)
加全局鎖的命令:Flush tables with read lock
,即 FTWRL。
全局鎖的主要使用場(chǎng)景是全庫(kù)的邏輯備份,加了全局鎖進(jìn)行備份時(shí)有一定的使用風(fēng)險(xiǎn):
1、若在主庫(kù)備份,備份期間只讀,會(huì)影響業(yè)務(wù);
2、若在從庫(kù)備份,從庫(kù)只讀,無(wú)法及時(shí)同步主可以的更新,造成主從不一致;
也許你還記得,我們?cè)谥爸v事務(wù)的時(shí)候,有一個(gè)隔離級(jí)別叫做可重復(fù)讀,也就是設(shè)置了隔離級(jí)別進(jìn)入事務(wù)后,別的事務(wù)更改數(shù)據(jù)不會(huì)影響當(dāng)前的讀取。
使用 mysqldump 命令,結(jié)合 --single-transaction
參數(shù),可以將隔離級(jí)別設(shè)置為:REPEATABLE READ。
并且隨后再執(zhí)行一條 START TRANSACTION 語(yǔ)句,讓整個(gè)數(shù)據(jù)在 dump 過(guò)程中保證數(shù)據(jù)的一致性,這個(gè)選項(xiàng)對(duì) InnoDB 的數(shù)據(jù)表很有用,且不會(huì)鎖表。
為了確保使用 --single-transaction 命令時(shí),最終 dump 文件的有效性。需沒(méi)有下列語(yǔ)句 ALTER TABLE, CREATE TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE,因?yàn)橐恢滦宰x不能隔離上述語(yǔ)句。所以如果在 dump 過(guò)程中,使用上述語(yǔ)句,可能會(huì)導(dǎo)致 dump 出來(lái)的文件數(shù)據(jù)不一致或者不可用。
為啥不直接使用 mysqldump --single-transaction 來(lái)備份?
因?yàn)椋行┮娌恢С质聞?wù)啊,比如 MyISAM 引擎,所以,現(xiàn)在大家都在力推用 InnoDB 替代 MyISAM。
set global readonly=true
也可以將全局表設(shè)為只讀狀態(tài),有啥區(qū)別呢?
首先,修改 global 變量的方式影響面更大,不建議使用。
另外,異常處理機(jī)制上和 FTWRL 有差異:
FTWRL 命令:客戶端異常斷開,MySQL 會(huì)自動(dòng)釋放全局鎖,整個(gè)庫(kù)回到正常更新的狀態(tài)
readonly 狀態(tài)下,客戶端發(fā)生異常,數(shù)據(jù)庫(kù)會(huì)一直保持 readonly 狀態(tài),導(dǎo)致整個(gè)庫(kù)長(zhǎng)時(shí)間處于不可寫狀態(tài)
FTWRL 前有讀寫的話 ,F(xiàn)TWRL 都會(huì)等待讀寫執(zhí)行完畢后才執(zhí)行
FTWRL 執(zhí)行的時(shí)候要刷臟頁(yè)的數(shù)據(jù)到磁盤,要保持?jǐn)?shù)據(jù)的一致性
執(zhí)行 FTWRL 時(shí)候會(huì)等待所有事務(wù)都提交完畢
語(yǔ)法
LOCK TABLES tbl_name ; # 不影響其他表的寫操作
解鎖也是:
UNLOCK TABLES;
注意點(diǎn):
這兩個(gè)語(yǔ)句在執(zhí)行的時(shí)候都需要注意個(gè)特點(diǎn),就是隱式提交的語(yǔ)句,在退出 mysql 終端的時(shí)候都會(huì)隱式的自動(dòng)執(zhí)行 unlock tables,也就是如果要讓表鎖定生效就必須一直保持對(duì)話。
lock tables 除了會(huì)限制別的線程的讀寫外,也會(huì)限制本線程接下來(lái)的操作對(duì)象
鎖住整個(gè)表的影響面較大
P.S. MYSQL 的 read lock 和 wirte lock
read-lock:允許其他并發(fā)的讀請(qǐng)求,但阻塞寫請(qǐng)求,即可以同時(shí)讀,但不允許任何寫,也叫共享鎖
write-lock:不允許其他并發(fā)的讀和寫請(qǐng)求,是排他的(exclusive),也叫獨(dú)占鎖
元數(shù)據(jù)鎖不需要顯式使用,在訪問(wèn)一個(gè)表的時(shí)候會(huì)自動(dòng)加上。
它的作用主要是保證讀寫的正確性。
表的增刪改查操作,需要先加 MDL 讀鎖;
表結(jié)構(gòu)變更操作,需要先加 MDL 寫鎖
MDL 讀鎖之間不互斥,多個(gè)線程可以同時(shí)對(duì)一張表增刪改查。
MDL 讀寫鎖之間、寫鎖之間是互斥的,用來(lái)保證變更表結(jié)構(gòu)操作的安全性。
如果有兩個(gè)線程要同時(shí)給一個(gè)表加字段,其中一個(gè)要等另一個(gè)執(zhí)行完才能開始執(zhí)行。
事務(wù)中的 MDL 鎖,在語(yǔ)句執(zhí)行開始時(shí)申請(qǐng),但是語(yǔ)句結(jié)束后并不會(huì)馬上釋放,而會(huì)等到整個(gè)事務(wù)提交后再釋放。
因此,需要避免長(zhǎng)事務(wù),因?yàn)殚L(zhǎng)事務(wù)會(huì)造成鎖一直不能釋放,后續(xù)的操作會(huì)堆積,這個(gè)庫(kù)的線程很快就會(huì)爆滿。
行鎖是引擎層實(shí)現(xiàn)的,像 MyISAM 引擎就直接不支持行鎖,這些引擎在并發(fā)控制只能用表鎖!
兩階段協(xié)議:
需要的時(shí)候加上
事務(wù)結(jié)束時(shí)釋放
當(dāng)需要鎖多個(gè)行時(shí),盡量把影響并發(fā)的鎖往后放,這樣可以最大程度的減少事務(wù)之間的鎖等待,提升并發(fā)度。
另外,InnoDB 的 行鎖建立在索引的基礎(chǔ)上,鎖的是索引。因此,如果更新的列沒(méi)建索引會(huì)鎖住整個(gè)表。
不同線程出現(xiàn)循環(huán)資源依賴,涉及的線程都在等待別的線程釋放資源。
死鎖對(duì)策
1、主動(dòng)等待超時(shí),由參數(shù) innodb_lock_wait_timeout
設(shè)置,但是業(yè)務(wù)無(wú)法等待;
2、主動(dòng)死鎖檢測(cè)(innodb_deadlock_detect=on
)
發(fā)生死鎖后,InnoDB 一般都可以檢測(cè)到,并使一個(gè)事務(wù)釋放鎖回退,另一個(gè)則可以獲取鎖完成事務(wù)。
另外,我們可以采取以下方式避免死鎖:
通過(guò)表級(jí)鎖來(lái)減少死鎖產(chǎn)生的概率;
多個(gè)程序盡量約定以相同的順序訪問(wèn)表(這也是解決并發(fā)理論中哲學(xué)家就餐問(wèn)題的一種思路);
同一個(gè)事務(wù)盡可能做到一次鎖定所需要的所有資源。
另外,死鎖檢測(cè)也非常耗費(fèi)資源,判斷會(huì)不會(huì)由于自己的加入導(dǎo)致了死鎖,這是一個(gè)時(shí)間復(fù)雜度是 O(n) 的操作。
比如有 1000 個(gè)并發(fā)線程要同時(shí)更新同一行,那么死鎖檢測(cè)操作就是 100 萬(wàn)這個(gè)量級(jí)的,這將消耗大量的 CPU 資源。
如何解決死鎖檢測(cè)耗費(fèi)資源的情況?
1、關(guān)掉死鎖檢測(cè),需要保證不會(huì)發(fā)生死鎖;
2、控制并發(fā),對(duì)應(yīng)相同行的更新,在進(jìn)入引擎之前排隊(duì);
數(shù)據(jù)庫(kù)服務(wù)端實(shí)現(xiàn),中間件實(shí)現(xiàn)
不要在客戶端實(shí)現(xiàn),因?yàn)榭蛻舳说臄?shù)量未知
改 MySQL 源碼
將熱更新的行數(shù)據(jù)拆分成邏輯上的多行來(lái)減少鎖沖突,但是業(yè)務(wù)復(fù)雜度可能會(huì)大大提高
引擎支持行鎖就行鎖,比如 innodb;
引擎不支持行鎖就表鎖,比如 myisam;
在 MySQL5.6 中,開始支持更多的 alter table 類型操作來(lái)避免 copy data,同時(shí)支持了在線上 DDL 的過(guò)程中不阻塞 DML 操作,真正意義上的實(shí)現(xiàn)了 Online DDL。
1、拿 MDL 寫鎖
2、降級(jí)成 MDL 讀鎖
3、真正做 DDL
4、升級(jí)成 MDL 寫鎖
5、釋放 MDL 鎖
1、2、4、5 如果沒(méi)有鎖沖突,執(zhí)行時(shí)間非常短。
第 3 步占用了 DDL 絕大部分時(shí)間,這期間這個(gè)表可以正常讀寫數(shù)據(jù),是因此稱為「online」
表級(jí)鎖:開銷小,加鎖快;不會(huì)出現(xiàn)死鎖;鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)度最低。
這些存儲(chǔ)引擎通過(guò)總是一次性同時(shí)獲取所有需要的鎖以及總是按相同的順序獲取表鎖來(lái)避免死鎖。
表級(jí)鎖更適合于以查詢?yōu)橹鳎l(fā)用戶少,只有少量按索引條件更新數(shù)據(jù)的應(yīng)用,如 Web 應(yīng)用
行級(jí)鎖:開銷大,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。
最大程度的支持并發(fā),同時(shí)也帶來(lái)了最大的鎖開銷。
在 InnoDB 中,除單個(gè) SQL 組成的事務(wù)外,鎖是逐步獲得的,這就決定了在 InnoDB 中發(fā)生死鎖是可能的。
行級(jí)鎖只在存儲(chǔ)引擎層實(shí)現(xiàn),而 Mysql 服務(wù)器層沒(méi)有實(shí)現(xiàn)。
行級(jí)鎖更適合于有大量按索引條件并發(fā)更新少量不同數(shù)據(jù),同時(shí)又有并發(fā)查詢的應(yīng)用,如一些在線事務(wù)處理(OLTP)系統(tǒng)
上述特點(diǎn)來(lái)看,很難說(shuō)哪種鎖更好,只能相對(duì)于所處的業(yè)務(wù)場(chǎng)景來(lái)選擇更加適合的鎖機(jī)制。
如果僅從鎖的角度來(lái)看,表級(jí)鎖更適合以查詢?yōu)橹鞯膽?yīng)用場(chǎng)景,而行級(jí)鎖則更適合于大量按索引條件并發(fā)更新少量數(shù)據(jù)的應(yīng)用場(chǎng)景。
對(duì)于平時(shí)常用的存儲(chǔ)引擎,MyISAM 采用的是表級(jí)鎖,InnoDB 采用的是行級(jí)鎖加表級(jí)鎖。
參考:
https://dwz.cn/oudQ7cM9
分享題目:MySQL實(shí)戰(zhàn)|06/07簡(jiǎn)單說(shuō)說(shuō)MySQL中的鎖
標(biāo)題URL:http://vcdvsql.cn/article22/pdiecc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App設(shè)計(jì)、外貿(mào)建站、外貿(mào)網(wǎng)站建設(shè)、手機(jī)網(wǎng)站建設(shè)、關(guān)鍵詞優(yōu)化、域名注冊(cè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)