InnoDB共享鎖和排它鎖(行鎖類型)

前言:

    最怕面試官問到一大堆的鎖概念了,表鎖、頁鎖、行鎖,排它鎖、共享鎖...

    有關於鎖的概念實在太多了,而我們在實際使用中使用到的又太少。很少有專門去寫特定類型的鎖實現,一般都是數據庫默認幫我們做了相應的鎖動作。

    本文就着示例把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.共享鎖與排它鎖之間是互不兼容的

 

參考:MySQL技術內幕 InnoDB存儲引擎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章