自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MySQL 中的表級鎖很差勁嗎?

數(shù)據(jù)庫 MySQL
說到 MyISAM 和 InnoDB 的區(qū)別,很多人都知道,區(qū)別在于一個是表鎖一個是行鎖,那么小伙伴們有沒有想過,表鎖和行鎖有什么區(qū)別?各自又有哪些玩法?今天松哥就來和大家聊聊這個話題。

[[409831]]

當(dāng)然不是!

其實本來今天是要和大家聊一聊 MyISAM 引擎的,結(jié)果在寫的過程中,又發(fā)現(xiàn)鎖這個話題可以單獨寫一篇,于是就有了今天的文章。

說到 MyISAM 和 InnoDB 的區(qū)別,很多人都知道,區(qū)別在于一個是表鎖一個是行鎖,那么小伙伴們有沒有想過,表鎖和行鎖有什么區(qū)別?各自又有哪些玩法?今天松哥就來和大家聊聊這個話題。

1.鎖

我們先來大致說一下 MySQL 中的鎖。

當(dāng)多個事務(wù)或者多個進(jìn)程訪問同一個資源的時候,為了保證數(shù)據(jù)的一致性,就需要用到 MySQL 鎖機制,從鎖定資源的角度來看,MySQL 中的鎖大致上可以分為三種:

  • 表級鎖(table-level locking):表級鎖的特點是開銷小,加鎖快,不會出現(xiàn)死鎖,但是鎖定粒度較大,發(fā)生鎖沖突的概率高,而且并發(fā)度也低。
  • 行級鎖(row-level locking):行級鎖的特點是開銷大,加鎖慢,有可能會出現(xiàn)死鎖,但是它的鎖定粒度小,發(fā)生鎖沖突的概率低,并發(fā)度也高。
  • 頁面鎖:開銷和加鎖時間界于表鎖和行鎖之間,會出現(xiàn)死鎖,鎖定粒度界于表鎖和行鎖之間,并發(fā)度一般。

雖然理論上有三種鎖,但是對于在坐的各位小伙伴包括松哥而言,我們?nèi)粘i_發(fā)接觸最多的還是前兩種,就是表級鎖和行級鎖。

在 MySQL 中,MyISAM 引擎是表級鎖,而 InnoDB 引擎則支持行級鎖,不過需要注意,其實 InnoDB 也支持表級鎖,只不過默認(rèn)情況下是行級鎖。

2.表級鎖

MySQL 的表級鎖有兩種模式:

表共享讀鎖(Table Read Lock)。

表獨占寫鎖(Table Write Lock)。

MyISAM 引擎在執(zhí)行 select 時會自動給相關(guān)表加讀鎖,在執(zhí)行 update、delete 和 insert 時會自動給相關(guān)表加寫鎖。

2.1 表共享讀鎖

我們先來看表共享讀鎖,加了共享讀鎖的表,不會阻塞其他 session 的讀請求,但是會阻塞其他 session 的寫請求。

我們來演示一下這個效果。

在下面的案例中,我們會準(zhǔn)備兩個窗口,代表兩個 session。

首先我們新建一張表,選擇 MyISAM 作為存儲引擎,DDL 如下:

  1. CREATE TABLE `user` ( 
  2.   `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
  3.   `namevarchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL
  4.   PRIMARY KEY (`id`) 
  5. ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 

添加一條測試數(shù)據(jù):

  1. insert into user(namevalues('javaboy'); 

然后我們在兩個命令行窗口分別登錄 mysql,模擬出兩個 session。

首先在第一個窗口為表添加讀鎖,如下:

  1. lock table user read

然后在第二個窗口去讀取數(shù)據(jù):

  1. select * from user

可以發(fā)現(xiàn),是可以正常讀取的。

然后我們嘗試在第二個窗口寫入一條數(shù)據(jù):

  1. insert into user(namevalues('itboyhub'); 

這條寫入語句會 卡住,如下:

卡住的原因是因為 user 表目前被上了共享讀鎖,這個時候需要我們?nèi)サ降谝粋€窗口中,解除表的鎖定,這個時候第二個窗口中的這條插入 sql 就可以執(zhí)行了。如下:

  1. unlock tables; 

當(dāng)這條 SQL 完畢后,第二個窗口中的插入語句立馬就執(zhí)行了。

如下是窗口2的截圖:

可以看到,加了共享讀鎖的表,不會阻塞其他 session 的讀(select)請求,但是會阻塞其他 session 的寫(insert、update、delete)請求。

需要注意的是,如果在同一條 SQL 中,同一個表名出線了 N 次,該表就要鎖定 N 次,如下:

思考:

我們在窗口 1 中給 user 表加了鎖,那么在窗口 1 中是否可以對 user 表執(zhí)行 insert/update/delete 等寫操作呢?評論區(qū) show 出你的答案~

2.2 表獨占寫鎖

這個獨占寫鎖就是大家鎖所熟知的排他鎖,它會阻塞其他進(jìn)程對同一表的讀寫操作,只有當(dāng)當(dāng)前鎖釋放后,才會執(zhí)行其他進(jìn)程的讀寫操作。

我們來演示一下這個過程。

還是兩個窗口,首先我們我們在第一個窗口中執(zhí)行鎖表操作:

  1. lock table user write; 

然后去第二個窗口中做查詢操作,如下:

可以看到,由于是排他鎖,所以查詢操作也被阻塞了。此時需要在窗口 1 中解除表的鎖定,窗口 2 中的查詢操作才會繼續(xù)執(zhí)行下去。

這就是表獨占寫鎖,也就是排他鎖。

在 MyISAM 存儲引擎中,會自動為 SELECT 語句加上共享鎖,為 update/delete/insert 操作加上排他鎖。

2.3 concurrent_insert

前面我們講的是表級鎖的兩種基本模式,在具體的使用過程中,我們還可以通過 concurrent_insert 去配置一些并發(fā)行為。

concurrent_insert 有三種不同的取值:

NEVER:加了讀鎖之后,不允許其他 session 并發(fā)插入。

AUTO:加了讀鎖之后,如果表里沒有刪除過數(shù)據(jù),其他 session 就可以并發(fā)插入。

ALWAYS:加了讀鎖之后,允許其他 session 并發(fā)插入。

需要注意的是,在 MySQL5.5.3 之前,NEVER、AUTO 以及 ALWAYS 分別使用 0、1、2 代替。

通過 show global variables like '%concurrent_insert%' 命令我們可以查看當(dāng)前數(shù)據(jù)庫中 concurrent_insert 的取值,如下:

可以看到,數(shù)據(jù)庫中默認(rèn)的 concurrent_insert 取值為 AUTO。有小伙伴可能會說,啥?AUTO?那為啥我在 2.1 小結(jié)中,當(dāng)表加了讀鎖之后,其他 session 無法插入數(shù)據(jù)呢?這其實跟加鎖方式有關(guān),我們一起來看下。

還是兩個窗口,首先我們在第一個窗口中為表添加讀鎖,如下:

  1. lock table user read local

可以看到,最后多了一個 local,這就是關(guān)鍵。

接下來我們在窗口 2 中去嘗試讀寫操作,如下:

從圖中可以看到,讀寫操作都可以順利執(zhí)行。

但是這個時候,如果我們?nèi)ゴ翱?1 中執(zhí)行查詢,如下:

可以看到,這里并看不到窗口 2 中剛剛添加的那條數(shù)據(jù),換句話說,窗口 2 中添加的數(shù)據(jù)對窗口 1 是不可以見的,必須等窗口 1 中的鎖釋放之后,才可以看到窗口 2 中添加的數(shù)據(jù)。

如下圖,釋放鎖之后,就可以看到另外一個窗口添加進(jìn)來的數(shù)據(jù)了:

這是我給大家演示的默認(rèn)的 concurrent_insert 的行為,大家也可以通過如下 SQL 修改該值:

  1. set global concurrent_insert = ALWAYS; 

2.4 鎖的優(yōu)先級

在 MyISAM 中,默認(rèn)情況下,寫鎖的優(yōu)先級要高,不過開發(fā)者也可以自行調(diào)整這個默認(rèn)鎖的優(yōu)先級。

話說回來,由于 MyISAM 是表鎖,所以不建議用在需要頻繁更新的場景下,否則可能會造成長時間的鎖等待。所以下面的優(yōu)先級調(diào)整,僅僅作為技術(shù)層面的探討。

修改 SQL 優(yōu)先級

首先我們可以在執(zhí)行 SQL 的時候,順便修改其優(yōu)先級:

例如執(zhí)行 select 的時候可以使用 HIGH_PRIORITY 來提高該語句的優(yōu)先級,如下:

在執(zhí)行 delete/update/insert 等操作的時候,可以使用 LOW_PRIORITY 來降低其優(yōu)先級,以便讓讀取操作先執(zhí)行:

當(dāng)然我們也可以通過如下 SQL 讓所有支持 LOW_PRIORITY 選項的語句都默認(rèn)地按照低優(yōu)先級來處理。

  1. set LOW_PRIORITY_UPDATES = 1 

修改寫鎖上限

我們可以修改 MAX_WRITE_LOCK_COUNT 的值,該變量默認(rèn)值如下圖:

這個值表示當(dāng)一個表的寫鎖數(shù)量達(dá)到給定的值后,就降低寫鎖的優(yōu)先級,讓讀鎖有機會執(zhí)行。如果有需要,我們可以自行調(diào)整這個值,調(diào)整方式如下:

  1. set GLOBAL MAX_WRITE_LOCK_COUNT=1024; 

3.行級鎖

行級鎖松哥留到講 InnoDB 的時候再和大家聊,今天我們就先扯這么多~

參考資料:

1.https://database.51cto.com/art/201910/604421.htm

2.https://zhuanlan.zhihu.com/p/123962424

本文轉(zhuǎn)載自微信公眾號「江南一點雨」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系江南一點雨公眾號。

 

責(zé)任編輯:武曉燕 來源: 江南一點雨
相關(guān)推薦

2020-02-06 10:02:45

MySQL數(shù)據(jù)庫全局鎖

2010-05-24 12:50:59

MySQL表級鎖

2024-11-29 07:38:12

MySQL數(shù)據(jù)庫

2022-10-24 00:33:59

MySQL全局鎖行級鎖

2025-02-10 09:58:48

2021-11-26 08:07:16

MySQL SQL 語句數(shù)據(jù)庫

2025-02-14 10:03:40

2024-03-04 00:01:00

鎖表鎖行MySQL

2010-11-22 14:27:05

MySQL鎖表

2023-12-26 08:17:04

Go框架Go 語言

2024-05-13 12:44:00

InnodbMySQL行級鎖

2020-04-28 08:55:11

MySQL數(shù)據(jù)庫

2010-11-22 14:42:13

MySQL行級鎖

2010-10-15 14:10:56

Mysql行級鎖

2010-05-24 12:26:26

MySQL鎖表

2018-07-31 10:10:06

MySQLInnoDB死鎖

2024-06-20 08:03:35

MySQL數(shù)據(jù)表版本

2020-10-20 13:50:47

MySQL數(shù)據(jù)庫

2013-03-20 18:14:35

架構(gòu)架構(gòu)設(shè)計項目

2010-01-21 17:14:40

C++兼容
點贊
收藏

51CTO技術(shù)棧公眾號