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

騰訊一面:MySQL的共享鎖和獨(dú)占鎖

數(shù)據(jù)庫(kù) MySQL
理解共享鎖(S鎖)和排他鎖(X鎖)的工作機(jī)制及其交互關(guān)系對(duì)于掌握MySQL的并發(fā)控制和鎖機(jī)制非常重要,因此,今天就來一起聊聊MySQL的共享鎖和排他鎖。

在InnoDB存儲(chǔ)引擎中,行級(jí)別鎖有兩種類型:共享鎖(S鎖)和排他鎖(X鎖),理解這 2種鎖的工作機(jī)制及其交互關(guān)系對(duì)于掌握MySQL的并發(fā)控制和鎖機(jī)制非常重要,因此,今天就來一起聊聊MySQL的共享鎖和排他鎖。

申明:本文基于 MySQL 8.0.30 版本,InnoDB引擎。

一、共享鎖

1.什么是共享鎖?

共享鎖(shared lock,S鎖),也叫讀鎖。它是指當(dāng)對(duì)象被鎖定時(shí),允許多個(gè)事務(wù)同時(shí)讀取該資源,也允許其它事務(wù)從該對(duì)象上再次獲取共享鎖,但不能對(duì)該對(duì)象進(jìn)行寫操作。

2.加鎖方式

共享鎖一般通過下面 2種方式進(jìn)行加鎖:

# 方式1
select ... lock in share mode;

# 方式2
select ... for share;

如果事務(wù)T1 持有某對(duì)象的共享(S)鎖,則事務(wù)T2 需要再次獲取該對(duì)象的鎖時(shí),會(huì)出現(xiàn)下面兩種情況:

  • 如果T2 獲取該對(duì)象的共享(S)鎖,則可以立即獲取鎖;
  • 如果T2 獲取該對(duì)象的排他(X)鎖,則無(wú)法獲取鎖;

二、舉例說明

為了更好地理解上述兩種情況,這里分別以下面的執(zhí)行順序流對(duì)InnoDB存儲(chǔ)引擎和MyISAM存儲(chǔ)引擎進(jìn)行驗(yàn)證:

1.InnoDB存儲(chǔ)引擎

創(chuàng)建一張用戶user表,表結(jié)構(gòu)如下:

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

(1) 給行加共享鎖

這里給user表中id=3行加共享鎖為例,執(zhí)行順序流如下表:

加鎖線程  sessionA

線程B  sessionB

線程C  sessionC

#開啟事務(wù)

begin;



#給id=3的行加共享鎖

select * from user

where id = 3 lock in share mode;




#獲取id=3行的共享鎖成功

#select操作執(zhí)行成功

select * from user where id=3;

#獲取id=3行的共享鎖成功

#select操作執(zhí)行成功

select * from user where id=3;


#獲取id=3行的排它鎖失敗

#delete操作被堵塞

delete from user where id = 3;

#獲取id=4行的排它鎖成功

#delete操作執(zhí)行成功

delete from user where id = 4;

#提交事務(wù)

#id=3的行上共享鎖被釋放

commit;




#獲取id=3行的排它鎖成功

#被堵塞的delete操作執(zhí)行成功

delete from user where id = 3;


示例執(zhí)行結(jié)果圖如下:

通過上述的示例執(zhí)行結(jié)果可以看出:當(dāng)事務(wù)A(sessionA)對(duì)user中id=3這行添加共享鎖后,事務(wù)B(sessionB)和事務(wù)C(sessionC)都可以獲取user表的共享鎖,也就是select操作能成功執(zhí)行,但是事務(wù)B(SessionB)獲取user表id=3的寫鎖失敗,即delete where id=3操作被阻塞,而事務(wù)C(sessionC)獲取user表id=4的寫鎖成功,即delete where id=4操作成功;

(2) 給表加共享鎖

這里通過lock in share mode方式給user整張表添加共享鎖,執(zhí)行順序流如下表:

加鎖線程   sessionA

線程B    sessionB

#開啟事務(wù)

begin;


#對(duì)user整張表加共享鎖

select * from user lock in share mode;



#成功獲取user表的共享鎖,select操作成功執(zhí)行

select * from user;


#獲取user表的排他鎖失敗,操作被堵塞

delete from user where id = 1;

#提交事務(wù)

#user表的共享鎖被釋放

commit;



#獲取user表上排他鎖成功,delete操作執(zhí)行成功

delete from user where id = 1;

示例執(zhí)行結(jié)果圖如下:

通過上述的示例執(zhí)行結(jié)果可以看出:當(dāng)事務(wù)A(sessionA)對(duì)user整張表添加共享鎖后,事務(wù)B(sessionB)可以獲取user表的共享鎖,也就是select操作能成功執(zhí)行,但是事務(wù)B(SessionB)獲取user表的寫鎖失敗,即delete操作被阻塞。

所以,盡管共享鎖(S鎖)是InnoDB存儲(chǔ)引擎的行級(jí)別鎖,但是一旦它作用到整張表時(shí),其實(shí)是對(duì)表中所有的行加共享鎖。

2.MyISAM引擎

創(chuàng)建一張用戶person表,表結(jié)構(gòu)如下:

CREATE TABLE `person` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(25) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_name` (`name`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_

給行加共享鎖

這里給person表的id=3行加共享鎖為例,執(zhí)行順序流如下表:

加鎖線程  sessionA

線程B  sessionB

#開啟事務(wù)

begin;


#給id=3的行加共享鎖

select * from person where id = 3 lock in share mode;



#獲取id=3行的共享鎖成功

#select操作成功

select * from person where id=3;


#獲取id=3行的排它鎖成功

#update操作成功

update person set name='name3xx' user where id = 3;


select * from person where id=3;

#提交事務(wù)

#id=3行上共享鎖被釋放

commit;


示例執(zhí)行結(jié)果圖如下:

通過上述的示例執(zhí)行結(jié)果可以看出:當(dāng)事務(wù)A(sessionA)對(duì)person中id=3這行添加共享鎖后,事務(wù)B(sessionB)既能獲取person表的共享鎖,也能獲取person表id=3的寫鎖,即select和update where id=3都操作成功;

因此,在MyISAM引擎中其實(shí)不存在共享鎖。

3.總結(jié)

通過上述示例及其運(yùn)行結(jié)果可以看出:

共享鎖是InnoDB存儲(chǔ)引擎的行級(jí)鎖,在MyISAM存儲(chǔ)引擎中不存在;

共享鎖是盡管是行級(jí)別鎖,但是當(dāng)鎖加在整個(gè)表時(shí)(表中所有的行,一種特殊的行),排他鎖也會(huì)在表級(jí)別生效;

三、排它鎖

1.什么是排他鎖?

排它鎖(exclusive lock,X鎖),也叫寫鎖或者獨(dú)占鎖,主要是防止其它事務(wù)和當(dāng)前加鎖事務(wù)鎖定同一對(duì)象,同一對(duì)象主要有兩層含義:

  • 當(dāng)排他鎖加在表上,則其它事務(wù)無(wú)法對(duì)該表進(jìn)行insert,update,delete,alter,drop等更新操作;
  • 當(dāng)排他鎖加在行上,則其它事務(wù)無(wú)法對(duì)該行進(jìn)行insert,update,delete,alter,drop等更新操作;

2.加鎖方式

排他鎖加鎖的方式一般有 2種:顯式加鎖和隱式加鎖,如下:

-- 顯式加鎖
select ... for update;

-- 隱式加鎖,是 MySQL內(nèi)部自動(dòng)加鎖

為了更好的說明排他鎖,這里以下面的執(zhí)行順序流來進(jìn)行驗(yàn)證,用戶user表的結(jié)構(gòu)還是和上面的一樣:

四、舉例說明

為了更好地理解上述兩種情況,這里分別以下面的執(zhí)行順序流對(duì)InnoDB存儲(chǔ)引擎和MyISAM存儲(chǔ)引擎進(jìn)行驗(yàn)證:

1.InnoDB存儲(chǔ)引擎

(1) 給行加排他鎖

這里通過for update顯式給user表中id=6行加排他鎖為例,執(zhí)行順序流如下表:

加鎖線程  sessionA

線程B  sessionB

線程C  sessionC

#開啟事務(wù)

begin;



#給id=6的行加排他鎖

select * from user

where id = 6 for update;




#獲取id=6的共享鎖成功

select * from user where id=6;

#獲取id=6的共享鎖成功

select * from user where id=6;


#獲取id=6的排它鎖失敗

delete from user where id = 6;

#獲取id=7的排它鎖成功

delete from user where id = 7;

#提交事務(wù)

#user表id=6的行上排他鎖被釋放

commit;




#獲取id=6的排它鎖成功

#被堵塞的delete操作執(zhí)行成功

delete from user where id = 6;


示例執(zhí)行結(jié)果圖如下:

通過上述的示例執(zhí)行結(jié)果可以看出:當(dāng)事務(wù)A(sessionA)對(duì)user中id=6這行添加共享鎖后,事務(wù)B(sessionB)和事務(wù)C(sessionC)都可以獲取user表的共享鎖,也就是select操作能成功執(zhí)行,但是事務(wù)B(SessionB)獲取user表id=6的寫鎖失敗,即delete where id=6操作被阻塞,而事務(wù)C(sessionC)獲取user表id=7的寫鎖成功,即delete where id=7操作成功;

(2) 給表加排他鎖

這里通過for update顯式方式給user整張表添加排他鎖,執(zhí)行順序流如下表:

加鎖線程   sessionA

線程B    sessionB

#開啟事務(wù) begin;


#對(duì)user整張表加排他鎖

select * from user for update;



#獲取user表上的共享鎖成功,select執(zhí)行成功

select * from user;


#獲取user表上的排他鎖失敗,操作被堵塞

delete from user where id=3;

#提交事務(wù)

#user表上的排他被釋放

commit;



#獲取user表上的排他鎖成功,操作執(zhí)行成功

delete from user where id = 3;

示例執(zhí)行結(jié)果圖如下:

通過上述的示例執(zhí)行結(jié)果可以看出:當(dāng)事務(wù)A(sessionA)對(duì)user整張表加排他鎖后,事務(wù)B(sessionB)可以獲取user表的共享鎖,也就是select操作能成功執(zhí)行,但是事務(wù)B(SessionB)獲取user表的排他鎖失敗,即delete操作被阻塞;

所以,盡管排他鎖(X鎖)是InnoDB存儲(chǔ)引擎的行級(jí)別鎖,但是一旦它作用到整張表時(shí),其實(shí)是對(duì)表中所有的行加排他鎖。

2.MySQL 隱式加排他鎖

這里通過MySQL隱式給user的id=6行添加排他鎖,執(zhí)行順序流如下表

加鎖線程   sessionA

線程B    sessionB

#開啟事務(wù) begin;


#MySQL隱式給id=6行加排他鎖

update user set name = 'name6' where id =6;



#獲取id=6的共享鎖失敗,select執(zhí)行被阻塞

select * from user where id = 6 lock in share mode;

#提交事務(wù)

#id=6的排他被釋放

commit;



#獲取id=6表上的共享鎖成功,select執(zhí)行成功;

示例執(zhí)行結(jié)果圖如下:

通過上述的示例執(zhí)行結(jié)果可以看出:當(dāng)事務(wù)A(sessionA)執(zhí)行update where id=6時(shí),MySQL會(huì)隱式加排他鎖,事務(wù)B(sessionB)在lock in share mode模式下獲取user表id=6的共享鎖失敗,也就是select操作能成功被阻塞;

3.MyISAM引擎

MySQL 隱式加排他鎖

這里通過MySQL隱式給person的id=4行添加排他鎖,執(zhí)行順序流如下表:

加鎖線程   sessionA

線程B    sessionB

#開啟事務(wù) begin;


#MySQL不會(huì)隱式給id=4行加排他鎖

update person set name = 'name4' where id =4;



#獲取id=4的共享鎖成功,select執(zhí)行成功

select * from user where id=4 lock in share mode;


#獲取id=4表上的共享鎖成功,select執(zhí)行成功;

#提交事務(wù) id=4的排他被釋放

commit;


示例執(zhí)行結(jié)果圖如下:

通過上述的示例執(zhí)行結(jié)果可以看出:當(dāng)事務(wù)A(sessionA)執(zhí)行update where id=6時(shí),MySQL不會(huì)隱式加排他鎖,事務(wù)B(sessionB)既能獲取id=4的共享鎖,也能獲取id=4的排他鎖;

因此,在MyISAM引擎中其實(shí)不存在排他鎖。

4.總結(jié)

通過上述 3個(gè)示例及其運(yùn)行結(jié)果可以看出:排他鎖有表級(jí)別共享鎖和行級(jí)別共享鎖和自動(dòng)鎖機(jī)制 3種 表級(jí)別共享鎖:

  • 鎖定整個(gè)表,排他鎖也會(huì)在表級(jí)別生效;
  • 行級(jí)別共享鎖:鎖定特定行,排他鎖也會(huì)在行級(jí)別生效;
  • 自動(dòng)鎖機(jī)制:根據(jù)操作是表級(jí)別還行級(jí)別自動(dòng)加對(duì)應(yīng)的鎖;

五、共享鎖和排他鎖的兼容性矩陣

為了更好地理解共享鎖和排他鎖的互斥關(guān)系,可以參考以下兼容性矩陣:


無(wú)鎖

共享鎖

排他鎖

無(wú)鎖

允許

允許

允許

共享鎖

允許

允許

阻塞

排他鎖

允許

阻塞

阻塞

從上述矩陣可以看出:

  • 無(wú)鎖狀態(tài)下可以獲取任何類型的鎖
  • 共享鎖狀態(tài)下可以繼續(xù)獲取共享鎖,但不能獲取排他鎖
  • 排他鎖狀態(tài)下不能獲取任何其他鎖

六、總結(jié)

  • 共享鎖(S鎖)和排他鎖(X鎖)是InnoDB存儲(chǔ)引擎中的 2種行級(jí)別鎖,MyISAM存儲(chǔ)引擎不存在。
  • 盡管共享鎖(S 鎖)和排他鎖(X 鎖)是行級(jí)鎖,但是當(dāng)他們加到表級(jí)別時(shí),對(duì)表所有行都生效,這樣看上去等同表級(jí)鎖
  • 共享鎖(S 鎖)允許多個(gè)事務(wù)同時(shí)讀取數(shù)據(jù),但不允許修改數(shù)據(jù)。多個(gè)事務(wù)可以同時(shí)持有共享鎖
  • 排他鎖(X 鎖)允許一個(gè)事務(wù)修改數(shù)據(jù)。只有一個(gè)事務(wù)可以持有排他鎖,并且在它釋放鎖之前,其他事務(wù)不能獲得任何類型的鎖
責(zé)任編輯:趙寧寧 來源: 猿java
相關(guān)推薦

2022-02-21 15:01:45

MySQL共享鎖獨(dú)占鎖

2024-01-29 07:43:42

Java獨(dú)占鎖共享鎖

2018-07-31 10:10:06

MySQLInnoDB死鎖

2024-05-15 09:23:45

MySQL排他鎖共享鎖

2019-01-04 11:18:35

獨(dú)享鎖共享鎖非公平鎖

2022-07-26 07:51:40

ThreadRunnableFuture

2024-06-11 00:01:00

并發(fā)validate場(chǎng)景

2020-10-20 13:50:47

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

2022-05-11 22:15:51

云計(jì)算云平臺(tái)

2009-07-30 14:38:36

云計(jì)算

2020-09-19 17:46:20

React Hooks開發(fā)函數(shù)

2020-09-03 11:10:34

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

2011-12-23 09:43:15

開源開放

2011-12-22 20:53:40

Android

2024-05-15 16:41:57

進(jìn)程IO文件

2024-10-30 16:12:14

2024-11-29 07:38:12

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

2023-12-06 07:33:20

MySQL鎖事間隙鎖

2022-11-30 17:13:05

MySQLDynamic存儲(chǔ)

2024-03-18 12:21:28

Java輕量級(jí)鎖重量級(jí)鎖
點(diǎn)贊
收藏

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