中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

什么是MySQL鎖機制

發布時間:2021-07-12 16:48:58 來源:億速云 閱讀:152 作者:chen 欄目:數據庫

本篇內容主要講解“什么是MySQL鎖機制”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“什么是MySQL鎖機制”吧!

無論什么時候,只要存在多個連接在同一時刻修改數據,都會涉及到并發控制的問題。MySQL實現了兩個層面的并發控制:服務層和引擎層。

鎖分類

按照使用場景分類

共享鎖:共享鎖(shared lock)也稱為讀鎖(read  lock)。共享鎖是共享的,或者說是相互不阻塞的。多個連接在同一時刻可以同時讀取同一個資源,而不相互干擾。

排他鎖:排他鎖(exclusive lock)也稱為寫鎖(write lock)。寫鎖是排他的,也就是一個寫鎖會阻塞其他的寫鎖和讀鎖。

按照加鎖思想分類

悲觀鎖:對數據被外界修改保持悲觀的態度,在整個數據處理過程中,數據都處于鎖定狀態。

樂觀鎖:它認為數據一般情況下不會造成沖突,在數據更新的時候才會對數據的沖突與否進行校驗。

按照鎖粒度分類

全局鎖:對整個數據庫實例加鎖,它將整個數據庫實例處于只讀的狀態。

表級鎖:對整個表進行加鎖的方式。MySQL表級鎖分為表鎖和元數據鎖。

行級鎖:行鎖可以最大程度的支持并發處理,行鎖是存儲引擎層實現的,而MySQL服務層并沒有實現行鎖。InnoDB存儲引擎行級鎖類型:Record  Lock、Gap Lock、Next-key Lock。

讀寫鎖

讀鎖

共享鎖:共享鎖(shared lock)也稱為讀鎖(read  lock)。共享鎖是共享的,或者說是相互不阻塞的。多個連接在同一時刻可以同時讀取同一個資源,而不相互干擾。

加鎖命令

select ...... lock in share mode;

測試

測試時,設置事務手動提交:set autocommit = 0,后續如果沒有明確的提示,autocommit都是0。

測試時,大家開啟兩個窗口,建立兩個連接,窗口1和窗口2分別對應事務A和事務B。

  • 窗口1:查詢id=6的行數據并添加讀鎖,正確返回數據。

  • 窗口2:依然查詢id=6的行數據并添加讀鎖,正確返回數據。讀讀不沖突。

  • 窗口1:對id=6的行執行寫操作(update語句),在窗口2的事務提交之前,寫操作阻塞,并可能會超時退出。

什么是MySQL鎖機制

如果寫鎖等待時間過長,則會超時退出。

窗口1 mysql> update user set age = 20 where id =6; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

如果在窗口1中的事務在執行寫操作等待期間,窗口2的事務也執行同一行數據的寫操作,則會導致死鎖錯誤。

窗口2 mysql> update user set age = 30 where id =6; ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

 寫鎖

排他鎖(exclusive lock)也稱為寫鎖(write lock)。寫鎖是排他的,也就是一個寫鎖會阻塞其他的寫鎖和讀鎖。

加鎖命令

select ...... for update;

測試

  • 窗口1:查詢id=6的行數據并添加寫鎖,正確返回數據。

  • 窗口2:依然查詢id=6的行數據并添加寫鎖,阻塞。寫寫沖突。

  • 窗口1:對id=6的行執行寫操作(update語句),寫操作未阻塞。

  • 窗口1事務提交之后,窗口2的查詢語句返回結果。

什么是MySQL鎖機制

悲觀鎖和樂觀鎖

不論是樂觀鎖還是悲觀鎖都是人們定義的一種概念,并不是一種鎖實現,它是一種思想。樂觀鎖比較適用于讀多寫少的場景,悲觀鎖適用于寫多讀少的場景。

悲觀鎖

當我們對數據庫的某一條數據進行修改操作時,為了避免同時有其他人對同一行數據進行修改,通過對數據進行加鎖的方式以防止并發問題。這種借助了數據庫的鎖機制,在修改數據之前先鎖定再修改的方式稱為悲觀鎖(Pessimistic  Lock)。

悲觀鎖具有強烈的獨占性和排他性,在整個數據的寫操作過程,都將數據處于鎖定狀態。悲觀鎖的實現往往需要數據庫提供的鎖機制。

悲觀鎖的實現:

  • 數據庫的鎖機制如行鎖、表鎖、讀鎖和寫鎖都是在操作之前先加鎖的操作,都屬于悲觀鎖。

  • Java中學習的synchronized關鍵字也是悲觀鎖。

樂觀鎖

樂觀鎖是相對于悲觀鎖的概念,樂觀鎖是假設數據一般情況下都不會存在并發沖突,在數據進行更新的時候才會對數據的沖突與否進行驗證。如果存在沖突,則告訴用戶結果,由用戶決定下一步該怎么做。

樂觀鎖是一種寬松的加鎖方式,它不需要使用數據庫本身的鎖機制。

樂觀鎖的實現:

  • MVCC,數據庫多版本控制利用版本號控制數據更新的并發問題,是樂觀鎖的實現。

  • CAS,比較并交換是Java中樂觀鎖的實現。

全局鎖

全局鎖:對整個數據庫實例加鎖,它將整個數據庫實例處于只讀的狀態。

加鎖命令 (FTWRL)

Flush tables with read lock;

應用場景

全局鎖常用來對整個數據庫實例進行邏輯備份。

全局鎖加鎖期間,業務的數據更新操作(DML)和 表結構的修改操作(DDL)都是會被鎖住的。

此時你是不是有個疑問:開發中備份都是直接使用mysqldump,什么時候使用FTWRL呢?

官方自帶的邏輯備份工具mysqldump 使用參數-single  -transaction的時候,在導出數據的時候就會啟動一個事務,來確保拿到一致性視圖,在學習事務隔離的時候我們了解到,基于MVCC的一致性視圖,這個過程中的數據是可以正常更新的。但是我們要知道事務是引擎層的實現,并不是每個存儲引擎都支持事務。我們在開發中大部分的備份使用的是mysqldump,主要是因為我們的存儲引擎大部分情況都是使用的默認的引擎InnoDB。

表級鎖

表級鎖:即是對整張表進行加鎖。表的定義包含兩個部分:數據和結構,所以表級鎖也分為兩類:表鎖和元空間鎖。

表鎖

表鎖是MySQL中最基本的鎖策略,并且也是開銷最小的策略。表鎖會鎖住整張表,在對表進行寫操作(插入、刪除、更新等)前,需要先獲取寫鎖,它會阻塞其他用戶對該表的所有讀寫操作。只有沒有寫鎖時,其他讀取的用戶才能獲取讀鎖。讀鎖之前互相不會造成阻塞。

寫鎖的優先級高于讀鎖,因此一個寫鎖的請求可能會被插入到讀鎖隊列前面,但是讀鎖是不能插入到寫鎖的前面的。

加解鎖命令

-- 對表加讀鎖 lock tables ...... read; -- 對表加寫鎖 lock tables ...... write; -- 釋放鎖 unlock tables;

 測試

表鎖讀鎖測試

  • 窗口1:對user表加讀鎖。

  • 窗口2:對user表全表讀取,正常返回全表數據。

  • 窗口2:修改user表中id=6的數據,阻塞。讀寫沖突。

  • 窗口1:修改user表中id=6的數據,報錯。

  • 窗口1:釋放讀鎖,窗口2的更新數據執行成功。

什么是MySQL鎖機制

表鎖寫鎖測試

  • 窗口1:對user表添加寫鎖。

  • 窗口2:全表查詢user表,阻塞。

  • 窗口1:更新user表中的id=6的數據,更新成功。

  • 窗口1:釋放鎖,窗口2的全表查詢返回最新數據。

什么是MySQL鎖機制

元空間鎖

MySQL5.5版本中引入了元空間鎖(matadata  lock),當對一個表做增刪改查操作的時候,會添加MDL讀鎖。當對表結構變更操作的時候,會添加MDL寫鎖。MDL的作用是防止DDL和DML并發的沖突。

MDL鎖是系統默認添加的,不需要顯式的添加。

測試

  • 窗口1:查詢表中的一條數據,這個時候在執行查詢語句,會添加MDL讀鎖。

  • 窗口2:添加字段,此時執行的是alter語句,會添加MDL寫鎖。這個時候窗口1的讀鎖沒有釋放,所以alter語句會阻塞。

  • 窗口3:查詢表中的一條數據,由于窗口2導致的阻塞,在窗口3申請MDL讀鎖的時候也會造成阻塞。

  • 窗口1:提交事務,窗口3獲取了MDL讀鎖,返回查詢結果。

  • 窗口3:提交事務釋放了讀鎖,窗口2獲取寫鎖,添加字段成功。

什么是MySQL鎖機制

行級鎖

MySQL的行鎖是在引擎層由各個存儲引擎實現的。并不是所有的存儲引擎都支持行鎖,比如MyISAM引擎是不支持行鎖的。不支持行鎖意味著并發控制的時候只能使用表鎖,這也意味著同一個時刻同一個表只有一個更新執行,嚴重影響了并發。InnoDB是支持行鎖的,這也是InnoDB能替代MyISM的重要原因之一。

兩階段鎖協議

在InnoDB事務,行鎖是需要的時候加上的,但并不是不需要了就立刻釋放的,而是需要等到事務結束后才會釋放鎖。這個就是兩階段鎖協議。

InnoDB是采用的兩階段鎖協議。在事務執行的過程中,隨時都可以鎖定,鎖只有在執行commit或者rollback的時候才會釋放,并且所有的鎖是在同一個時刻釋放的。

什么是MySQL鎖機制

事務A執行了兩條update語句之后,事務B也執行update語句,但是事務B阻塞直到事務A提交事務。

行鎖

我們創建一張簡單表t,其中id為主鍵,a為索引,插入6條數據。

CREATE TABLE `t1` (   `id` int(11) NOT NULL,   `a` int(11) DEFAULT NULL,   `b` int(11) DEFAULT NULL,   PRIMARY KEY (`id`),   KEY `idx` (`a`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; insert into t1 values(0,0,0),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25);

 間隙鎖(Gap Lock)

間隙鎖,鎖的是兩個值的間隙。

對于表t1,6條數據就產生了7個間隙,如下圖所示:

什么是MySQL鎖機制

我們看前面學習的寫鎖的例子:

begin; select * from t1 where b = 5 for update; commit;
  • 加了寫鎖的select查詢是當前讀,讀取的是最新的數據值。

  • b字段不是表的索引字段,它會掃描全表將滿足條件的行都加上寫鎖,也會給滿足條件的行兩邊的間隙加上了鎖。

間隙鎖之間并不會沖突,與間隙鎖存在沖突關系的是往這個間隙中插入數據的操作。

next-key lock

行鎖和間隙鎖的合稱為next-key lock每個next-key  lock都是一個前開后閉的區間。這里不要混淆了,間隙鎖是一個開區間,間隙鎖加上行鎖生成的next-key lock是一個前開后閉的區間。

間隙鎖和next-key lock的引入幫助我們解決了幻讀的問題。

間隙鎖是可重復隔離級別下才生效的,如果我們把隔離級別設置為讀提交,那就沒有間隙鎖了。

測試

前面我們在學習其他鎖的時候,為了省事把autocommit設置為了0,現在我們需要把autocommit設置為1;

  • 窗口1:使用顯式事務,通過for update加寫鎖,對滿足條件的行和間隙加鎖。

  • 窗口2:更新id為0的行,此行沒有加鎖更新成功。

  • 窗口3:插入數據,滿足了(0,5]的next-key lock,阻塞等待。

什么是MySQL鎖機制

總結

鎖按照鎖粒度分為:全局鎖、表鎖和行鎖。

行鎖是引擎層的實現,我們文中描述的行鎖都是基于InnoDB存儲引擎的實現。

InnoDB的行鎖采用的兩階段鎖協議,鎖在需要的時候添加,只有在事務commit或者rollback時才會一次性釋放所有鎖。

可重復度隔離級別下存在間隙鎖,如果設置為其他的隔離級別下就沒有間隙鎖了。間隙鎖即是對行數據的兩邊間隙進行加鎖,間隙鎖加上行鎖合稱為next-key  lock,它是一個前開后閉的區間。間隙鎖解決了幻讀的問題。

大家在學習鎖的時候還需多動手實踐。

到此,相信大家對“什么是MySQL鎖機制”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

东辽县| 出国| 荥经县| 界首市| 嫩江县| 临夏市| 荣昌县| 湘潭市| 永川市| 桐城市| 灌阳县| 台东县| 福清市| 周至县| 土默特左旗| 巴林左旗| 公安县| 荔波县| 汉沽区| 安仁县| 维西| 班玛县| 云梦县| 松滋市| 西畴县| 潮州市| 云霄县| 安吉县| 巴林右旗| 开原市| 剑川县| 瓮安县| 靖安县| 含山县| 定边县| 博罗县| 金溪县| 黔西| 安丘市| 福州市| 上林县|