Innodb:為什麼lock in share mode在show engine看不到行鎖資訊
水平有限 有誤請指出
版本:Percona MySQL 5.7.22
對於鎖的學習我做了一些輸出詳細參考如下:
其中有readme
一、問題提出
不知道有沒有朋友和我一樣用lock in share mode做加鎖實驗,但是卻在show engine innodb status中看不到加鎖資訊,今天剛好有朋友在問@在樹枝上吹風,今天就做了一下簡單的debug,因為我也挺納悶的。(我喜歡多問一個為什麼也挺累的)
問題如下:
首先我開啟了我的列印行鎖引數,讓加鎖輸出到日誌中
mysql> show variables like '%gaopeng%'; +--------------------------------+-------+| Variable_name | Value | +--------------------------------+-------+ | gaopeng_mdl_detail | OFF || innodb_gaopeng_row_lock_detail | ON | +--------------------------------+-------+
然後跑如下語句
mysql> show create table t \G *************************** 1. row *************************** Table: t Create Table: CREATE TABLE `t` ( `id` int(11) NOT NULL, `c` int(11) DEFAULT NULL, `d` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `c` (`c`) ) ENGINE=InnoDB DEFAULT CHARSET=utf81 row in set (0.00 sec) mysql> select * from t; +----+------+------+| id | c | d |+----+------+------+| 0 | 0 | 0 || 5 | 5 | 5 || 10 | 10 | 10 || 15 | 15 | 15 || 20 | 20 | 20 || 25 | 25 | 25 |+----+------+------+6 rows in set (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.01 sec) mysql> select * from t where id=0 lock in share mode; +----+------+------+| id | c | d |+----+------+------+| 0 | 0 | 0 |+----+------+------+1 row in set (4.21 sec)
按理說這個時候應該在主鍵ID=0這一行上了LOCK_S,但是show engine innodb卻看不到加鎖資訊如下:
------------ TRANSACTIONS ------------ Trx id counter 241482 Purge done for trx's n:o < 241482 undo n:o < 0 state: running but idle History list length 182 Total number of lock structs in row lock hash table 1 LIST OF TRANSACTIONS FOR EACH SESSION: ---TRANSACTION 422211785606640, not started 0 lock struct(s), heap size 1160, 0 row lock(s) ---TRANSACTION 422211785605248, not started 0 lock struct(s), heap size 1160, 0 row lock(s) -------- FILE I/O --------
根本看不到加鎖資訊。但是我的日誌中卻有輸出如下:
2019-03-20T14:37:41.980845+08:00 10 [Note] InnoDB: TRX ID:(0) table:test/t index:PRIMARY space_id: 95 page_id:3 heap_no:2 row lock mode:LOCK_S|LOCK_NOT_GAP| PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 4; hex 80000000; asc ;; 1: len 6; hex 00000003676a; asc gj;; 2: len 7; hex d8000000330110; asc 3 ;; 3: len 4; hex 80000000; asc ;; 4: len 4; hex 80000000; asc ;;
因此我基本斷定加鎖肯定是做了的,但是為什麼沒有輸出呢?
二、分析
我開始懷疑是否是提前釋放了或者是列印的時候過濾掉了?後來發現都不是。看了到了一個TRX_ID為422211785605248,這是隻讀事物的TRX_ID的形式,會不是因為應列印的時候只會列印讀寫的事物的鎖結構資訊,因為Innodb中讀寫事物有一個獨立的連結串列,如果只列印這個連結串列上的資訊就會出現這個問題。接著我做了一個事物先做了一個delete操作然後做lock in share mode語句可以看到LOCK_S結構就可以看到了,如下:
mysql> begin; Query OK, 0 rows affected (2.43 sec) mysql> delete from t2 limit 1; ##這個語句我就顯示的開始了一個讀寫事物Query OK, 1 row affected (3.53 sec) mysql> select * from t where id=0 lock in share mode; +----+------+------+| id | c | d |+----+------+------+| 0 | 0 | 0 |+----+------+------+1 row in set (2.98 sec) mysql>
再來看看
---TRANSACTION 422211785606640, not started0 lock struct(s), heap size 1160, 0 row lock(s) ---TRANSACTION 422211785605248, not started0 lock struct(s), heap size 1160, 0 row lock(s) ---TRANSACTION 241482, ACTIVE 85 sec4 lock struct(s), heap size 1160, 2 row lock(s), undo log entries 1MySQL thread id 10, OS thread handle 140737153423104, query id 391 localhost root TABLE LOCK table `test`.`t2` trx id 241482 lock mode IX RECORD LOCKS space id 33 page no 19 n bits 624 index GEN_CLUST_INDEX of table `test`.`t2` trx id 241482 lock_mode X(LOCK_X) locks rec but not gap(LOCK_REC_NOT_GAP) Record lock, heap no 447 PHYSICAL RECORD: n_fields 4; compact format; info bits 32 0: len 6; hex 00000000451d; asc E ;; 1: len 6; hex 00000003af4a; asc J;; 2: len 7; hex 3c000000453040; asc < E0@;; 3: len 4; hex 80000001; asc ;; TABLE LOCK table `test`.`t` trx id 241482 lock mode IS RECORD LOCKS space id 95 page no 3 n bits 80 index PRIMARY of table `test`.`t` trx id 241482 lock mode S(LOCK_S) locks rec but not gap(LOCK_REC_NOT_GAP) Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 4; hex 80000000; asc ;; 1: len 6; hex 00000003676a; asc gj;; 2: len 7; hex d8000000330110; asc 3 ;; 3: len 4; hex 80000000; asc ;; 4: len 4; hex 80000000; asc ;;
我們看到了 lock mode S(LOCK_S) locks rec but not gap(LOCK_REC_NOT_GAP)的資訊看來沒有問題,猜測是實驗是一樣的,但是還是要原始碼驗證一下。
三、原始碼驗證
-
1、列印函式lock_print_info_all_transactions
/*********************************************************************//** Prints info of locks for each transaction. This function assumes that the caller holds the lock mutex and more importantly it will release the lock mutex on behalf of the caller. (This should be fixed in the future). */voidlock_print_info_all_transactions(/*=============================*/ FILE* file) /*!< in/out: file where to print */{ ut_ad(lock_mutex_own()); fprintf(file, "LIST OF TRANSACTIONS FOR EACH SESSION:\n"); mutex_enter(&trx_sys->mutex); /* First print info on non-active transactions */ /* NOTE: information of auto-commit non-locking read-only transactions will be omitted here. The information will be available from INFORMATION_SCHEMA.INNODB_TRX. */ PrintNotStarted print_not_started(file);//建立一個結構體,目的是做not start 事物的列印 ut_list_map(trx_sys->mysql_trx_list, print_not_started); //這個地方列印出那些事物狀態是no start的事物,但是這裡存在一個問題,等會看程式碼在看。mysql_trx_list是全事物。 const trx_t* trx; TrxListIterator trx_iter; //這個迭代器是trx_sys->rw_trx_list 這個連結串列的迭代器 const trx_t* prev_trx = 0; /* Control whether a block should be fetched from the buffer pool. */ bool load_block = true; bool monitor = srv_print_innodb_lock_monitor && (srv_show_locks_held != 0); while ((trx = trx_iter.current()) != 0) { //透過迭代器進行迭代 ,顯然這裡不會有隻讀事物的資訊。 check_trx_state(trx); if (trx != prev_trx) { lock_trx_print_wait_and_mvcc_state(file, trx); prev_trx = trx; /* The transaction that read in the page is no longer the one that read the page in. We need to force a page read. */ load_block = true; } /* If we need to print the locked record contents then we need to fetch the containing block from the buffer pool. */ if (monitor) { /* Print the locks owned by the current transaction. */ TrxLockIterator& lock_iter = trx_iter.lock_iter(); if (!lock_trx_print_locks( file, trx, lock_iter, load_block)) { /* Resync trx_iter, the trx_sys->mutex and the lock mutex were released. A page was successfully read in. We need to print its contents on the next call to lock_trx_print_locks(). On the next call to lock_trx_print_locks() we should simply print the contents of the page just read in.*/ load_block = false; continue; } } load_block = true; /* All record lock details were printed without fetching a page from disk, or we didn't need to print the detail. */ trx_iter.next(); } lock_mutex_exit(); mutex_exit(&trx_sys->mutex); ut_ad(lock_validate()); }
這個函式是呼叫的邏輯。
-
結構體PrintNotStarted括號過載
void operator()(const trx_t* trx) { ut_ad(trx->in_mysql_trx_list); ut_ad(mutex_own(&trx_sys->mutex)); /* See state transitions and locking rules in trx0trx.h */ if (trx_state_eq(trx, TRX_STATE_NOT_STARTED)) {//這裡我們發現只有狀態為TRX_STATE_NOT_STARTED才會進行輸出 fputs("---", m_file); trx_print_latched(m_file, trx, 600); } }
我們這裡可以看到只有狀態為TRX_STATE_NOT_STARTED才會輸出為not start狀態。
TrxListIterator迭代器初始化程式碼
TrxListIterator() : m_index() { /* We iterate over the RW trx list first. */ m_trx_list = &trx_sys->rw_trx_list; }
我們這裡可以看到只有讀寫事物才會進行鎖結構的輸出。
四、問題總結
我發現既然如此,我們show engine innodb status的事物部分的輸出中我們發現會列印出如下資訊:
- 事物狀態是not start的事物資訊
- 正在執行的讀寫事物的資訊包括鎖資訊
但是如果只讀事物事物狀態為running狀態的呢?這裡就不列印了,但是這其實是一個比較關鍵的資訊,這個時候只有在innodb_trx 檢視中去看了如下:
mysql> select * from INNODB_TRX \G; *************************** 1. row *************************** trx_id: 422211785602464 trx_state: RUNNING trx_started: 2019-03-20 15:21:54...
真是因為如此lock in share mode 事物在show engine innodb 是看不到的,因為壓根不會列印,除非先顯示開啟一個讀寫事物。而對於 for update 這種上LOCK_X鎖的事物會歸入讀寫事物因此可以列印出來。
最後吐槽一下show engine innodb 事物列印部分應該可以改進啊。
作者微信:gp_22389860
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7728585/viewspace-2638875/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MySQL 共享鎖 (lock in share mode),排他鎖 (for update)MySql
- MySQL的show engine innodb statusMySql
- show engine innodb status操作解析之一
- 深入理解SELECT ... LOCK IN SHARE MODE和SELECT ... FOR UPDATE
- show engine innodb status 輸出結果解讀
- mysql innodb lock鎖之record lock之一MySql
- MySQL自增列鎖模式 innodb_autoinc_lock_mode不同引數下效能測試MySql模式
- MySQL:5.6 大事務show engine innodb status故障一例MySql
- Innodb: 自動開啟列印show engine status到err日誌
- 使用show engine innodb status 檢視記憶體使用情況記憶體
- Percona 8.0.30中"show engine innodb status"導致coredump排查及分析
- Innodb中怎麼檢視鎖資訊
- 技術分享 | show engine innodb status中Pages flushed up to 的含義
- ORACLE基礎之oracle鎖(oracle lock mode)詳解Oracle
- ORACLE LOCK MODE 1.2.3.4.5.6Oracle
- 行業資訊:為什麼選擇IT行業,在這裡找到答案!行業
- MySQL鎖:03.InnoDB行鎖MySql
- 為什麼dispatch_sync在主執行緒會死鎖執行緒
- 為什麼要這樣寫final ReentrantLock lock = this.lock; ?ReentrantLock
- MySQL鎖:InnoDB行鎖需要避免的坑MySql
- MySQL next-key lock 加鎖範圍是什麼?MySql
- 我們為什麼需要 lock 檔案
- 為什麼Java有了synchronized之後還造了Lock鎖這個輪子?Javasynchronized
- Lock 鎖
- 頭位資訊平臺在使用者鎖定上有什麼妙招?
- Mysql研磨之InnoDB行鎖模式MySql模式
- 設定mysql 事務鎖超時時間 innodb_lock_wait_timeoutMySqlAI
- InnoDB常用鎖總結(行鎖、間隙鎖、臨鍵鎖、表鎖)
- InnoDB LOCK檢視變化
- synchronized 作為悲觀鎖,鎖住了什麼?synchronized
- MySQL:Innodb 讓MDL LOCK和ROW LOCK 記錄到errlogMySql
- mysql metadata lock後設資料鎖之鎖狀態lock_status流轉圖MySql
- MySQL中MyISAM為什麼比InnoDB查詢快MySql
- mysql死鎖deadlock相關幾個系統變數innodb_lock_wait_timeoutMySql變數AI
- 什麼是行為資料?企業為什麼要使用它?
- 詳細瞭解INNODB_TRX、INNODB_LOCKs、INNODB_LOCK_waits、PROCESSLIST表AI
- 為什麼在 Plasma 上難以執行 EVMASM
- Lock鎖之重入鎖與讀寫鎖