mysql中鎖機(jī)制的最全面講解
前言
根據(jù)加鎖的粒度區(qū)分
- 全局鎖
- 表級(jí)鎖
- 行鎖
- 記錄鎖
- 間隙鎖
- 臨鍵鎖
根據(jù)加鎖的場(chǎng)景
- 樂觀鎖
- 悲觀鎖
全局鎖
鎖對(duì)象是:整個(gè)數(shù)據(jù)庫實(shí)例
Flush tables with read lock (FTWRL)-會(huì)讓整個(gè)庫處于只讀狀態(tài)
使用場(chǎng)景: 做全庫邏輯備份
全庫邏輯備份
為什么要進(jìn)行全局鎖才能進(jìn)行數(shù)據(jù)備份呢?
就比如售賣,我一張表記錄發(fā)貨,一張表記錄扣款.結(jié)果我在備份發(fā)貨記錄表.這個(gè)時(shí)候有人買東西了,只扣款了但是沒有發(fā)貨記錄.這個(gè)顯然是不行的
官方自帶的邏輯備份工具是mysqldump。當(dāng)mysqldump使用參數(shù)–single-transaction的時(shí)候,導(dǎo) 數(shù)據(jù)之前就會(huì)啟動(dòng)一個(gè)事務(wù),來確保拿到一致性視圖。而由于MVCC的支持,這個(gè)過程中數(shù)據(jù)是 可以正常更新的。但是這個(gè)是基于事務(wù)的基礎(chǔ)上的,針對(duì)myisam數(shù)據(jù)引擎就不可用,那么就有可能出現(xiàn)有的表不是基于innoDB的數(shù)據(jù)引擎
當(dāng)然,如果全部都是innodb的數(shù)據(jù)引擎表,那么,還是使用默認(rèn)的mysqldump增加參數(shù)–single-transaction來進(jìn)行全局邏輯備份的好
FTWRL和set global readonly=true的區(qū)別
- readonly會(huì)在別的邏輯中參與使用(不同系統(tǒng)不一樣)
- ftwrl可以在客戶端鏈接斷開時(shí),自動(dòng)釋放鎖.防止造成死鎖問題
表級(jí)鎖
命令:lock table {tableName} read/write(write比read權(quán)限大,能write當(dāng)然能read),unlock table解鎖
鎖住的資源只允許當(dāng)前的線程可以執(zhí)行對(duì)應(yīng)的操作.且當(dāng)前線程只能對(duì)鎖住的表進(jìn)行對(duì)應(yīng)的操作
例如:lock table t1 read,則當(dāng)前線程只能讀不能寫,其他線程不能讀不能寫
MDL鎖
不需要顯式使用,在訪問表時(shí)自動(dòng)加上(為了防止表結(jié)構(gòu)變更帶來的問題)
在對(duì)一張表進(jìn)行增刪改查時(shí)上MDL讀鎖,在對(duì)一張表的結(jié)構(gòu)進(jìn)行變更時(shí)上MDL寫鎖
- MDL讀鎖(共享鎖),鎖之間不互斥.所以可以允許多個(gè)線程進(jìn)行同時(shí)的增刪改查
- MDL寫鎖(排它鎖),這個(gè)鎖和其他讀寫鎖都互斥.也就是當(dāng)前數(shù)據(jù)變更或者查詢或者結(jié)構(gòu)變更,都必須等其他的MDL寫鎖釋放后才能執(zhí)行
行鎖
行鎖是引擎層,各個(gè)引擎自己實(shí)現(xiàn)的(MyISAM不支持行鎖,所以該引擎只能一次進(jìn)行一個(gè)線程的update操作)
在事務(wù)中:行鎖會(huì)在需要使用某一行或多行數(shù)據(jù)時(shí)加上,但是所有的行鎖都會(huì)在該事務(wù)提交才會(huì)釋放也就是說,別的線程需要訪問改行數(shù)據(jù),就需要等待線程的事務(wù)提交之后才能訪問
舉例:
線程A執(zhí)行以下操作
begin;
update t1 set a=1 where id=1;update t2 set b=2 where id=2;
commit
這個(gè)時(shí)候線程A分別對(duì)t1的id=1上鎖和t2的id=2上鎖.如果此時(shí)線程B訪問t1的id=1是無法訪問的,即使第一條語句已經(jīng)執(zhí)行完成了
線程B只有在線程A進(jìn)行了commit操作之后才能獲取其中的數(shù)據(jù)
所以,對(duì)于我們來說需要注意的點(diǎn)就是:在進(jìn)行事務(wù)操作時(shí),如果update沒有順序操作,那么就盡量將訪問最多的那條語句最后執(zhí)行(因?yàn)樯湘i是順序上的,但是釋放鎖是一起釋放的)
| 特點(diǎn) | 表鎖 | 行鎖 |
|---|---|---|
| 加鎖層面 | mysql的server層 | 數(shù)據(jù)引擎層 |
| 引擎 | MyISAM、innoDB | InnoDB |
| 特點(diǎn) | 不會(huì)死鎖、開銷小、加鎖快、鎖粒度大 | 易死鎖、開銷大、加鎖慢、鎖粒度小 |
死鎖
很多情況都回引起死鎖,大部分都是針對(duì)數(shù)據(jù)庫操作有問題才會(huì)導(dǎo)致.比如
線程A和線程B都針對(duì)id=1和id=2進(jìn)行修改并開啟事務(wù)
線程A先修改了id=1導(dǎo)致id=1被線程A上鎖
線程B修改了id=2導(dǎo)致id=2被縣城B上鎖
此時(shí)線程A要等待id=2釋放鎖后執(zhí)行對(duì)id=2的操作
而線程B要等待id=1釋放鎖后懟id=1的操作從而達(dá)到了一個(gè)循環(huán)死鎖的情況
處理這種問題有兩個(gè)策略:
- 直接進(jìn)入等待,直到超時(shí)。這個(gè)超時(shí)時(shí)間可以通過參數(shù) innodb_lock_wait_timeout(默認(rèn)50s)來設(shè)置。這個(gè)不能設(shè)置太短,如果不是死鎖呢?
- 發(fā)起死鎖檢測(cè),發(fā)現(xiàn)死鎖后,主動(dòng)回滾死鎖鏈條中的某一個(gè)事務(wù),讓其他事 務(wù)得以繼續(xù)執(zhí)行。將參數(shù)innodb_deadlock_detect設(shè)置為on(默認(rèn)就是on),表示開啟這個(gè)邏輯。
記錄鎖
屬于行鎖的一種情況
針對(duì)的是事務(wù)在加鎖后鎖住的某一條記錄信息
觸發(fā)情況:查詢條件精準(zhǔn)命中且命中的條件字段是唯一的
例如:update t1 set name="張三" where id=12138
作用:記錄在被當(dāng)前事務(wù)管理時(shí),加上鎖之后不會(huì)被其他事務(wù)獲取產(chǎn)生“重復(fù)讀”和“數(shù)據(jù)臟讀”的問題
間隙鎖
屬于行鎖的一種情況
間隙的意思就是between中的數(shù)據(jù)

在主鍵索引id中有多個(gè)數(shù)據(jù)未填充,這個(gè)時(shí)候如果兩個(gè)線程A和B,A在查詢0-10之間的數(shù)據(jù),而B在往id=3插入數(shù)據(jù),就會(huì)造成數(shù)據(jù)臟讀的問題

所以在進(jìn)行between等范圍查找的是事務(wù)時(shí)候,會(huì)加間隙鎖進(jìn)行約束
臨鍵鎖
臨鍵鎖會(huì)把查詢出來的記錄鎖住,同時(shí)也會(huì)把該范圍查詢內(nèi)的所有間隙空間也會(huì)鎖住,再之它會(huì)把相鄰的下一個(gè)區(qū)間也會(huì)鎖住。
(臨就是相鄰的意思)
樂觀鎖和悲觀鎖
| 概念 | 樂觀鎖 | 悲觀鎖 |
|---|---|---|
| 概念 | 假定不會(huì)發(fā)生并發(fā)沖突 只在提交時(shí)判斷下是否有數(shù)據(jù)問題 |
假定會(huì)發(fā)生并發(fā)沖突 從而上鎖 |
| 實(shí)現(xiàn)層面 | 業(yè)務(wù)代碼層面,自己實(shí)現(xiàn) (需要結(jié)合具體業(yè)務(wù)邏輯) |
mysql數(shù)據(jù)庫自身實(shí)現(xiàn) |
| 并發(fā)情況 | 并發(fā)大 | 并發(fā)小 |
| 實(shí)現(xiàn)方式 | 在數(shù)據(jù)庫中增加版本號(hào)字段, 提交時(shí)判斷操作前的版本號(hào)和當(dāng)前版本號(hào)是否一致 |
共享鎖:select lock xxxxxx 排它鎖:select xxxx for update |
| 其他 | mysql中的synchronized其實(shí)就是排它鎖 共享鎖:運(yùn)行其他線程查不允許增刪改 排它鎖:增刪改都不允許 |
總結(jié)
到此這篇關(guān)于mysql中鎖機(jī)制的文章就介紹到這了,更多相關(guān)mysql鎖機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用MySQL生成最近24小時(shí)整點(diǎn)時(shí)間臨時(shí)表
MySQL臨時(shí)表是一種只存在于當(dāng)前數(shù)據(jù)庫連接或會(huì)話期間的表,它們可以被用來存儲(chǔ)臨時(shí)數(shù)據(jù),這些數(shù)據(jù)可以在查詢中被使用,但是它們不會(huì)在數(shù)據(jù)庫中永久存儲(chǔ),這篇文章主要給大家介紹了關(guān)于如何使用MySQL生成最近24小時(shí)整點(diǎn)時(shí)間臨時(shí)表的相關(guān)資料,需要的朋友可以參考下2024-01-01
MySQL數(shù)據(jù)庫備份和還原的常用命令小結(jié)
MySQL數(shù)據(jù)庫備份和還原的常用命令小結(jié),學(xué)習(xí)mysql的朋友可以參考下2012-03-03
MySQL 一次執(zhí)行多條語句的實(shí)現(xiàn)及常見問題
通常情況MySQL出于安全考慮不允許一次執(zhí)行多條語句(但也不報(bào)錯(cuò),很讓人郁悶)。2009-08-08
深入探索數(shù)據(jù)庫MySQL性能優(yōu)化與復(fù)雜查詢相關(guān)操作
數(shù)據(jù)庫MySQL 是一種開源的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),在進(jìn)行 MySQL 數(shù)據(jù)庫開發(fā)過程中,需要深入了解如何進(jìn)行性能優(yōu)化和復(fù)雜查詢,以提高系統(tǒng)的效率和可靠性,本文介紹的非常詳細(xì),需要的朋友可以參考一下2023-04-04
解決Navicat Premium 連接 MySQL 8.0 報(bào)錯(cuò)"1251"的問題分析
這篇文章主要介紹了解決Navicat Premium 連接 MySQL 8.0 報(bào)錯(cuò)"1251"的問題分析,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11

