前言:
最怕面試官問到一大堆的鎖概念了,表鎖、頁鎖、行鎖,排它鎖、共享鎖...
有關於鎖的概念實在太多了,而我們在實際使用中使用到的又太少。很少有專門去寫特定類型的鎖實現,一般都是數據庫默認幫我們做了相應的鎖動作。
本文就着示例把InnoDB中的行鎖的兩種標準實現:共享鎖和排它鎖分析一下
準備:
1)筆者新建了張表(實際是copy的其他表),city_copy表,主鍵爲ID,自增長模式,默認從1開始。表創建SQL如下:
CREATE TABLE `city_copy` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Name` char(35) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '',
`CountryCode` char(3) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '',
`District` char(20) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '',
`Population` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`ID`) USING BTREE,
INDEX `CountryCode`(`CountryCode`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4080 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic;
2)有關於InnoDB事務和鎖記錄的幾張表
information_schema.INNODB_TRX:事務信息表
information_schema.INNODB_LOCKS:鎖信息表
information_schema.INNODB_LOCK_WAITS:鎖等待信息表
1.共享鎖事務之間的讀取
1)session1(共享鎖)
set autocommit=0; ##首先就是關閉自動提交
select * from city where id < 4 lock in share mode; ##以共享模式讀取數據
select * from information_schema.INNODB_TRX; ##查詢事務信息
查詢事務結果值:
可以看到,當前SQL執行完成之後存在已經RUNNING(運行中)的事務,鎖定記錄數爲4行
2)session2(共享鎖)
與session1執行相同的動作
set autocommit=0; ##首先就是關閉自動提交
select * from city where id < 4 lock in share mode; ##以共享模式讀取數據
select * from information_schema.INNODB_TRX; ##查詢事務信息
結果就是:出現兩條RUNNING事務記錄,兩個select語句分別都執行成功,獲取到結果值。
兩個session分別執行commit之後,運行中的事務信息消息。說明事務結束。
總結:共享鎖與共享鎖之間是相互兼容的。
2.共享鎖與排它鎖的事務示例
1)session1(共享鎖)
set autocommit=0; ##首先就是關閉自動提交
select * from city where id < 4 lock in share mode; ##以共享模式讀取數據
select * from information_schema.INNODB_TRX; ##查詢事務信息
session1執行共享鎖讀取方式,結果與1相同,不再展示
2)session2(排它鎖)
set autocommit=0; ##首先就是關閉自動提交
select * from city where id < 4 for update; ##以排它鎖的方式讀取
select * from information_schema.INNODB_TRX; ##查詢事務信息
// res 事務結果值如下
trx_id trx_state trx_started trx_requested_lock_id trx_wait_started trx_weight trx_mysql_thread_id trx_query trx_operation_state trx_tables_in_use trx_tables_locked trx_lock_structs trx_lock_memory_bytes trx_rows_locked trx_rows_modified trx_concurrency_tickets trx_isolation_level trx_unique_checks trx_foreign_key_checks trx_last_foreign_key_error trx_adaptive_hash_latched trx_adaptive_hash_timeout trx_is_read_only trx_autocommit_non_locking
462611 LOCK WAIT 2019-12-28 18:01:58 462611:50:5:2 2019-12-28 18:01:58 2 9 select * from city where id < 4 for update starting index read 1 1 2 1136 1 0 0 REPEATABLE READ 1 1 0 0 0 0
284711444560536 RUNNING 2019-12-28 18:01:38 2 10 select * from information_schema.INNODB_TRX 0 1 2 1136 4 0 0 REPEATABLE READ 1 1 0 0 0 0
根據事務結果值可以看到,與之前的狀態有所不同
id=284711444560536的事務是session1的共享鎖事務;
id=462611的事務是session中的排它鎖事務,目前是鎖等待狀態(表現形式就是目前獲取不到select結果值,一直在轉圈執行),這個會一直等待session1鎖釋放或者session2鎖超時時候回滾。
總結:共享鎖與排他鎖是互不兼容的。
讀者也可以試試,先執行session2再執行session1,結果值也是互不兼容的。
總結:
1.我們首先需要記住的是:共享鎖和排它鎖都是行鎖類型,所以上述的例子都是鎖定id <4的這些數據行,如果兩個session鎖定的是不同的行記錄,那麼就不存在兼不兼容的問題了。
2.排它鎖的獲取方式除了上述例子中的select ... for update,還有就是update 、delete操作
3.共享鎖與共享鎖之間是相互兼容的
4.共享鎖與排它鎖之間是互不兼容的