这篇文章主要介绍“Innodb中为什么lock in share mode在show engine看不到行锁信息”,在日常操作中,相信很多人在Innodb中为什么lock in share mode在show engine看不到行锁信息问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Innodb中为什么lock in share mode在show engine看不到行锁信息”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一、问题提出

不知道有没有朋友和我一样用lock in share mode做加锁实验,但是却在show engine innodb status中看不到加锁信息,今天刚好有朋友在问@在树枝上吹风,今天就做了一下简单的debug,因为我也挺纳闷的。(我喜欢多问一个为什么也挺累的)
问题如下:
首先我开启了我的打印行锁参数,让加锁输出到日志中

mysql>showvariableslike'%gaopeng%';+--------------------------------+-------+|Variable_name|Value|+--------------------------------+-------+|gaopeng_mdl_detail|OFF||innodb_gaopeng_row_lock_detail|ON|+--------------------------------+-------+

然后跑如下语句

mysql>showcreatetablet\G***************************1.row***************************Table:tCreateTable:CREATETABLE`t`(`id`int(11)NOTNULL,`c`int(11)DEFAULTNULL,`d`int(11)DEFAULTNULL,PRIMARYKEY(`id`),KEY`c`(`c`))ENGINE=InnoDBDEFAULTCHARSET=utf81rowinset(0.00sec)mysql>select*fromt;+----+------+------+|id|c|d|+----+------+------+|0|0|0||5|5|5||10|10|10||15|15|15||20|20|20||25|25|25|+----+------+------+6rowsinset(0.00sec)mysql>begin;QueryOK,0rowsaffected(0.01sec)mysql>select*fromtwhereid=0lockinsharemode;+----+------+------+|id|c|d|+----+------+------+|0|0|0|+----+------+------+1rowinset(4.21sec)

按理说这个时候应该在主键ID=0这一行上了LOCK_S,但是show engine innodb却看不到加锁信息如下:

------------TRANSACTIONS------------Trxidcounter241482Purgedonefortrx'sn:o<241482undon:o<0state:runningbutidleHistorylistlength182Totalnumberoflockstructsinrowlockhashtable1LISTOFTRANSACTIONSFOREACHSESSION:---TRANSACTION422211785606640,notstarted0lockstruct(s),heapsize1160,0rowlock(s)---TRANSACTION422211785605248,notstarted0lockstruct(s),heapsize1160,0rowlock(s)--------FILEI/O--------

根本看不到加锁信息。但是我的日志中却有输出如下:

2019-03-20T14:37:41.980845+08:0010[Note]InnoDB:TRXID:(0)table:test/tindex:PRIMARYspace_id:95page_id:3heap_no:2rowlockmode:LOCK_S|LOCK_NOT_GAP|PHYSICALRECORD:n_fields5;compactformat;infobits00:len4;hex80000000;asc;;1:len6;hex00000003676a;ascgj;;2:len7;hexd8000000330110;asc3;;3:len4;hex80000000;asc;;4:len4;hex80000000;asc;;

因此我基本断定加锁肯定是做了的,但是为什么没有输出呢?

二、分析

我开始怀疑是否是提前释放了或者是打印的时候过滤掉了?后来发现都不是。看了到了一个TRX_ID为422211785605248,这是只读事物的TRX_ID的形式,会不是因为应打印的时候只会打印读写的事物的锁结构信息,因为Innodb中读写事物有一个独立的链表,如果只打印这个链表上的信息就会出现这个问题。接着我做了一个事物先做了一个delete操作然后做lock in share mode语句可以看到LOCK_S结构就可以看到了,如下:

mysql>begin;QueryOK,0rowsaffected(2.43sec)mysql>deletefromt2limit1;##这个语句我就显示的开始了一个读写事物QueryOK,1rowaffected(3.53sec)mysql>select*fromtwhereid=0lockinsharemode;+----+------+------+|id|c|d|+----+------+------+|0|0|0|+----+------+------+1rowinset(2.98sec)mysql>

再来看看

---TRANSACTION422211785606640,notstarted0lockstruct(s),heapsize1160,0rowlock(s)---TRANSACTION422211785605248,notstarted0lockstruct(s),heapsize1160,0rowlock(s)---TRANSACTION241482,ACTIVE85sec4lockstruct(s),heapsize1160,2rowlock(s),undologentries1MySQLthreadid10,OSthreadhandle140737153423104,queryid391localhostrootTABLELOCKtable`test`.`t2`trxid241482lockmodeIXRECORDLOCKSspaceid33pageno19nbits624indexGEN_CLUST_INDEXoftable`test`.`t2`trxid241482lock_modeX(LOCK_X)locksrecbutnotgap(LOCK_REC_NOT_GAP)Recordlock,heapno447PHYSICALRECORD:n_fields4;compactformat;infobits320:len6;hex00000000451d;ascE;;1:len6;hex00000003af4a;ascJ;;2:len7;hex3c000000453040;asc<E0@;;3:len4;hex80000001;asc;;TABLELOCKtable`test`.`t`trxid241482lockmodeISRECORDLOCKSspaceid95pageno3nbits80indexPRIMARYoftable`test`.`t`trxid241482lockmodeS(LOCK_S)locksrecbutnotgap(LOCK_REC_NOT_GAP)Recordlock,heapno2PHYSICALRECORD:n_fields5;compactformat;infobits00:len4;hex80000000;asc;;1:len6;hex00000003676a;ascgj;;2:len7;hexd8000000330110;asc3;;3:len4;hex80000000;asc;;4:len4;hex80000000;asc;;

我们看到了 lock mode S(LOCK_S) locks rec but not gap(LOCK_REC_NOT_GAP)的信息看来没有问题,猜测是实验是一样的,但是还是要源码验证一下。

三、源码验证1、打印函数lock_print_info_all_transactions

/*********************************************************************//**Printsinfooflocksforeachtransaction.Thisfunctionassumesthatthecallerholdsthelockmutexandmoreimportantlyitwillreleasethelockmutexonbehalfofthecaller.(Thisshouldbefixedinthefuture).*/voidlock_print_info_all_transactions(/*=============================*/FILE*file)/*!<in/out:filewheretoprint*/{ut_ad(lock_mutex_own());fprintf(file,"LISTOFTRANSACTIONSFOREACHSESSION:\n");mutex_enter(&trx_sys->mutex);/*Firstprintinfoonnon-activetransactions*//*NOTE:informationofauto-commitnon-lockingread-onlytransactionswillbeomittedhere.TheinformationwillbeavailablefromINFORMATION_SCHEMA.INNODB_TRX.*/PrintNotStartedprint_not_started(file);//建立一个结构体,目的是做notstart事物的打印ut_list_map(trx_sys->mysql_trx_list,print_not_started);//这个地方打印出那些事物状态是nostart的事物,但是这里存在一个问题,等会看代码在看。mysql_trx_list是全事物。consttrx_t*trx;TrxListIteratortrx_iter;//这个迭代器是trx_sys->rw_trx_list这个链表的迭代器consttrx_t*prev_trx=0;/*Controlwhetherablockshouldbefetchedfromthebufferpool.*/boolload_block=true;boolmonitor=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;/*Thetransactionthatreadinthepageisnolongertheonethatreadthepagein.Weneedtoforceapageread.*/load_block=true;}/*Ifweneedtoprintthelockedrecordcontentsthenweneedtofetchthecontainingblockfromthebufferpool.*/if(monitor){/*Printthelocksownedbythecurrenttransaction.*/TrxLockIterator&lock_iter=trx_iter.lock_iter();if(!lock_trx_print_locks(file,trx,lock_iter,load_block)){/*Resynctrx_iter,thetrx_sys->mutexandthelockmutexwerereleased.Apagewassuccessfullyreadin.Weneedtoprintitscontentsonthenextcalltolock_trx_print_locks().Onthenextcalltolock_trx_print_locks()weshouldsimplyprintthecontentsofthepagejustreadin.*/load_block=false;continue;}}load_block=true;/*Allrecordlockdetailswereprintedwithoutfetchingapagefromdisk,orwedidn'tneedtoprintthedetail.*/trx_iter.next();}lock_mutex_exit();mutex_exit(&trx_sys->mutex);ut_ad(lock_validate());}

这个函数是调用的逻辑。

结构体PrintNotStarted括号重载

voidoperator()(consttrx_t*trx){ut_ad(trx->in_mysql_trx_list);ut_ad(mutex_own(&trx_sys->mutex));/*Seestatetransitionsandlockingrulesintrx0trx.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(){/*WeiterateovertheRWtrxlistfirst.*/m_trx_list=&trx_sys->rw_trx_list;}

我们这里可以看到只有读写事物才会进行锁结构的输出。

到此,关于“Innodb中为什么lock in share mode在show engine看不到行锁信息”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!