MySQL锁简介

备注:测试数据库版本为MySQL 8.0

这个blog我们来聊聊MySQL 事务

一.MySQL锁概述

数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则。对于任何一种数据库来说都需要有相应的锁定机制,所以MySQL自然也不能例外。MySQL数据库由于其自身架构的特点,存在多种数据存储引擎,每种存储引擎所针对的应用场景特点都不太一样,为了满足各自特定应用场景的需求,每种存储引擎的锁定机制都是为各自所面对的特定场景而优化设计,所以各存储引擎的锁定机制也有较大区别。MySQL各存储引擎使用了三种类型(级别)的锁定机制:表级锁定,行级锁定和页级锁定。

1.表级锁定(table-level)

表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,所以可以很好的避免困扰我们的死锁问题。

当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并大度大打折扣。

使用表级锁定的主要是MyISAM,MEMORY,CSV等一些非事务性存储引擎。

2.行级锁定(row-level)

行级锁定最大的特点就是锁定对象的颗粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的。由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。

虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。

使用行级锁定的主要是InnoDB存储引擎。

3.页级锁定(page-level)

页级锁定是MySQL中比较独特的一种锁定级别,在其他数据库管理软件中也并不是太常见。页级锁定的特点是锁定颗粒度介于行级锁定与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力也同样是介于上面二者之间。另外,页级锁定和行级锁定一样,会发生死锁。

在数据库实现资源锁定的过程中,随着锁定资源颗粒度的减小,锁定相同数据量的数据所需要消耗的内存数量是越来越多的,实现算法也会越来越复杂。不过,随着锁定资源颗粒度的减小,应用程序的访问请求遇到锁等待的可能性也会随之降低,系统整体并发度也随之提升。

使用页级锁定的主要是BerkeleyDB存储引擎。

总的来说,MySQL这3种锁的特性可大致归纳如下:

表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;

行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高;

页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

适用:从锁的角度来说,表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web应用;而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些在线事务处理(OLTP)系统。

二.InnoDB的八种锁

目前MySQL最常使用且支持事务的存储引擎是InnoDB,此处介绍InnoDB存储引擎的锁

锁类别 描述
Shared and Exclusive Locks 共享锁/排他锁
Intention Locks 意向共享锁/意向排他锁
Record Locks 行锁
Gap Locks 间隙锁
Next-Key Locks 临键锁
Insert Intention Locks 插入意向锁
AUTO-INC Locks 自增锁
Predicate Locks for Spatial Indexes 空间索引使用,本文暂不讨论

2.1 共享锁/排他锁

共享锁:S
排他锁:X

共享锁允许锁的持有者读取一行,其他事务可以获取共享锁读取数据,但是不能获取此条数据的排他锁
排他锁允许锁的持有者更新或删除一行,不允许其他事务获取该行的排他锁,只能等待该事物结束,其他事务才可以获取该行的排他锁

2.2 意向共享锁/意向排他锁

意向共享锁:IS
意向排他锁:IX

IS:事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁
IX:事务打算给数据行加排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁

共享锁/排他锁与意向共享锁/意向排他锁的兼容性关系:


image.png

2.3 行锁

A record lock is a lock on an index record. For example, SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE; prevents any other transaction from inserting, updating, or deleting rows where the value of t.c1 is 10.

行锁是一个索引记录上的锁。
举例: SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE
上面的语句,阻止其他事务 inserting, updating, or deleting 数据行在 t.c1 = 10 这行数据上

A record lock is a lock on an index record. Record locks always lock index records, even if a table is defined with no indexes. For such cases, InnoDB creates a hidden clustered index and uses this index for record locking.

这句话说明行锁一定是作用在索引上的。

2.4 间隙锁

间隙锁,在索引记录间隙上的锁,或者是第一条索引记录之前、最后一条索引记录之后上的间隙锁

测试案例来自 《丁奇45讲》

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;
insert into t values (0,0,0),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25);

对列d的锁定

session A session B 描述
begin;
select * from t where d = 5 for update;
mysql> insert into t values (1,1,5);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into t values (100,100,100);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into t values (-1,-1,-1);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
insert 全部失败了

因为列d没有索引,select * from t where d = 5 for update; 的时候会一行一行的查找,一行一行的加锁,直到锁定全表,那么这个锁什么时候释放呢,一直要到事务结束的时候才释放,也就是这条语句相当于 select * from t for update的效果。

对列c的锁定

session A session B 描述
begin;
select * from t where c = 5 for update;
mysql> insert into t values (4,5,5);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into t values (4,4,4);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>
mysql> insert into t values (6,6,6);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
这些insert都失败了
mysql> insert into t values (11,11,11);
Query OK, 1 row affected (0.01 sec)
这个insert成功了
mysql> insert into t values (6,0,6);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into t values (6,10,6);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
这两个临界点的insert 也都失败了
mysql> insert into t values (2,11,2);
Query OK, 1 row affected (0.01 sec)
mysql> insert into t values (4,11,4);
Query OK, 1 row affected (0.01 sec)
mysql> insert into t values (6,11,6);
Query OK, 1 row affected (0.01 sec)
只会影响C列的非等值insert a、d列不受影响

insert into t values (4,5,5);
上面这个insert语句失败,可以理解,因为session A锁住了 c=5的这一行,为了避免幻读的出现,insert c=5是会失败的。
insert into t values (4,4,4); insert into t values (6,6,6);
上面2个语句为什么又失败了呢?
insert into t values (11,11,11);
上面这个insert为什么又成功了呢?

行锁只会给行加锁
也就是说,即使把所有的记录都加上锁,还是阻止不了新插入的记录

InnoDB只好引入新的锁 间隙锁 Gap Lock 开区间

表t 插入了6个记录,这就产生了7个间隙


image.png

跟间隙锁存在冲突关系的,是“往这个间隙中插入一个记录"


image.png

select * from t where c=5 for update 其实限制了 c的值0-10的insert 包含0和10

InnoDB使用间隙锁的目的:

防止幻读,以满足相关隔离级别的要求;
满足恢复和复制的需要:
MySQL 通过 BINLOG 录入执行成功的 INSERT、UPDATE、DELETE 等更新数据的 SQL 语句,并由此实现 MySQL 数据库的恢复和主从复制。MySQL 的恢复机制(复制其实就是在 Slave Mysql 不断做基于 BINLOG 的恢复)有以下特点:

一是 MySQL 的恢复是 SQL 语句级的,也就是重新执行 BINLOG 中的 SQL 语句。
二是 MySQL 的 Binlog 是按照事务提交的先后顺序记录的, 恢复也是按这个顺序进行的。

由此可见,MySQL 的恢复机制要求:在一个事务未提交前,其他并发事务不能插入满足其锁定条件的任何记录,也就是不允许出现幻读。

2.5 临键锁(next key lock)

临键锁,索引记录锁以及索引记录之间的间隙锁,二者的组合锁

间隙锁和行锁合称为 next-key lock
每个 next-key lock是前开后闭区间

上例中的表t
select * froim t for update
形成了7个next-key lock
(-∞,0}、(0,5】、(5,10】、(10,15】、(15,20】、(20,25】、(25,+supermum)

+supermum为什么不是∞,因为是后闭的空间,可以理解为一个不存在的最大值

2.6 插入意向锁

意向锁是一种特殊的间隙锁,但不同于间隙锁的是,该锁只用于并发插入操作。如果说间隙锁锁住的是一个区间,那么插入意向锁锁住的就是一个点。因而从这个角度来说,插入意向锁确实是一种特殊的间隙锁。与间隙锁的另一个非常重要的差别是:尽管插入意向锁也属于间隙锁,但两个事务却不能在同一时间内一个拥有间隙锁,另一个拥有该间隙区间内的插入意向锁(当然,插入意向锁如果不在间隙锁区间内则是可以的)。

session A session B 描述
CREATE TABLE child (id int(11) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB;
INSERT INTO child (id) values (90),(102);
START TRANSACTION;
SELECT * FROM child WHERE id > 100 FOR UPDATE;
START TRANSACTION;
mysql> INSERT INTO child (id) VALUES (101);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> SHOW ENGINE INNODB STATUS \G
*************************** 1. row ***************************
  Type: InnoDB
  Name:
Status:
=====================================
2020-06-26 16:25:35 0x59d4 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 53 seconds
-----------------
BACKGROUND THREAD
-----------------
srv_master_thread loops: 89 srv_active, 0 srv_shutdown, 107334 srv_idle
srv_master_thread log flush and writes: 0
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 12
OS WAIT ARRAY INFO: signal count 10
RW-shared spins 4, rounds 4, OS waits 0
RW-excl spins 21, rounds 100, OS waits 1
RW-sx spins 0, rounds 0, OS waits 0
Spin rounds per wait: 1.00 RW-shared, 4.76 RW-excl, 0.00 RW-sx
------------
TRANSACTIONS
------------
Trx id counter 22279
Purge done for trx's n:o < 22277 undo n:o < 0 state: running but idle
History list length 6
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 281475316584688, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 281475316582144, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 22278, ACTIVE 337 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 14, OS thread handle 17448, query id 296 localhost ::1 root update
INSERT INTO child (id) VALUES (101)
------- TRX HAS BEEN WAITING 3 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 114 page no 4 n bits 72 index PRIMARY of table `test1`.`child` trx id 22278 lock_mode X locks gap before rec in
Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 80000066; asc    f;;
 1: len 6; hex 000000005700; asc     W ;;
 2: len 7; hex 82000000d6011d; asc        ;;

------------------
---TRANSACTION 22277, ACTIVE 351 sec
2 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 13, OS thread handle 11248, query id 287 localhost ::1 root
--------
FILE I/O
--------
I/O thread 0 state: wait Windows aio (insert buffer thread)
I/O thread 1 state: wait Windows aio (log thread)
I/O thread 2 state: wait Windows aio (read thread)
I/O thread 3 state: wait Windows aio (read thread)
I/O thread 4 state: wait Windows aio (read thread)
I/O thread 5 state: wait Windows aio (read thread)
I/O thread 6 state: wait Windows aio (write thread)
I/O thread 7 state: wait Windows aio (write thread)
I/O thread 8 state: wait Windows aio (write thread)
I/O thread 9 state: wait Windows aio (write thread)
Pending normal aio reads: [0, 0, 0, 0] , aio writes: [0, 0, 0, 0] ,
 ibuf aio reads:, log i/o's:, sync i/o's:
Pending flushes (fsync) log: 0; buffer pool: 0
1082 OS file reads, 2147 OS file writes, 1090 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 0.00 writes/s, 0.00 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
 insert 0, delete mark 0, delete 0
discarded operations:
 insert 0, delete mark 0, delete 0
Hash table size 34679, node heap has 0 buffer(s)
Hash table size 34679, node heap has 0 buffer(s)
Hash table size 34679, node heap has 0 buffer(s)
Hash table size 34679, node heap has 0 buffer(s)
Hash table size 34679, node heap has 0 buffer(s)
Hash table size 34679, node heap has 0 buffer(s)
Hash table size 34679, node heap has 1 buffer(s)
Hash table size 34679, node heap has 3 buffer(s)
0.00 hash searches/s, 0.02 non-hash searches/s
---
LOG
---
Log sequence number          64214586
Log buffer assigned up to    64214586
Log buffer completed up to   64214586
Log written up to            64214586
Log flushed up to            64214586
Added dirty pages up to      64214586
Pages flushed up to          64214586
Last checkpoint at           64214586
602 log i/o's done, 0.00 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 137363456
Dictionary memory allocated 471528
Buffer pool size   8192
Free buffers       6950
Database pages     1238
Old database pages 465
Modified db pages  0
Pending reads      0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 0, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 1049, created 189, written 1214
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 1238, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
--------------
ROW OPERATIONS
--------------
0 queries inside InnoDB, 0 queries in queue
0 read views open inside InnoDB
Process ID=21004, Main thread ID=0000000000001F54 , state=sleeping
Number of rows inserted 47, updated 6, deleted 3, read 289
0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s
Number of system rows inserted 136, updated 419, deleted 51, read 5155
0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================

1 row in set (0.00 sec)

2.7 自增锁

自增锁是一种特殊的表级锁,主要用于事务中插入自增字段,也就是我们最常用的自增主键id。

三.InnoDB加锁方法

意向锁是 InnoDB 自动加的, 不需用户干预。
对于 UPDATE、 DELETE 和 INSERT 语句, InnoDB会自动给涉及数据集加排他锁(X);
对于普通 SELECT 语句,InnoDB 不会加任何锁;
事务可以通过以下语句显式给记录集加共享锁或排他锁:
共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。
其他 session 仍然可以查询记录,并也可以对该记录加 share mode 的共享锁。
但是如果当前事务需要对该记录进行更新操作,则很有可能造成死锁。
排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE。
其他 session 可以查询该记录,但是不能对该记录加共享锁或排他锁,而是等待获得锁

3.1 隐式锁

InnoDB在事务执行过程中,使用两阶段锁协议:
随时都可以执行锁定,InnoDB会根据隔离级别在需要的时候自动加锁
锁只有在执行commit或者rollback的时候才会释放,并且所有的锁都是在同一时刻被释放。

3.2 显式锁定

select ... lock in share mode //共享锁 
select ... for update //排他锁 

select for update:

在执行这个 select 查询语句的时候,会将对应的索引访问条目进行上排他锁(X 锁),也就是说这个语句对应的锁就相当于update带来的效果。

select *** for update 的使用场景:为了让自己查到的数据确保是最新数据,并且查到后的数据只允许自己来修改的时候,需要用到 for update 子句。

select lock in share mode :in share mode 子句的作用就是将查找到的数据加上一个 share 锁,这个就是表示其他的事务只能对这些数据进行简单的select 操作,并不能够进行 DML 操作。select *** lock in share mode 使用场景:为了确保自己查到的数据没有被其他的事务正在修改,也就是说确保查到的数据是最新的数据,并且不允许其他人来修改数据。但是自己不一定能够修改数据,因为有可能其他的事务也对这些数据 使用了 in share mode 的方式上了 S 锁。

性能影响:
select for update 语句,相当于一个 update 语句。在业务繁忙的情况下,如果事务没有及时的commit或者rollback 可能会造成其他事务长时间的等待,从而影响数据库的并发使用效率。
select lock in share mode 语句是一个给查找的数据上一个共享锁(S 锁)的功能,它允许其他的事务也对该数据上S锁,但是不能够允许对该数据进行修改。如果不及时的commit 或者rollback 也可能会造成大量的事务等待。

四.死锁

死锁产生原因:
1.产生回路
两个或两个以上的事务执行过程中,分别持有一把锁,然后加另一把锁(AB-BA),产生死锁。
2.加锁顺序不一致
两个或两个以上的事务并发执行(同一时刻),因争夺锁资源而造成的一种相互等待,产生死锁。

测试sql:

create table t1(id int primary key,name varchar(20));
insert into t1 values (1,'AAAAA'),(2,'BBBBB');
session A session B 描述
begin;
update t1 set name = 'DDDDD' where id = 2;
begin;
update t1 set name = 'DDDDD' where id = 2;
update t1 set name = 'ddddd' where id = 2; 被锁住
update t1 set name = 'CCCCC' where id = 1;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
session A被锁住的执行成功,此条语句直接报死锁,整个事务被回滚了

减少死锁:
1.自动死锁检测,优先回滚小事务
2.超时设置(参数innodb_lock_wait_timeout)
3.尽快提交事务,小事务不容易发生死锁
4.加for update、lock in share mode读锁时,最好降低事务隔离级别,例如用RC级别,降低死锁发生概率
5.事务中设计多个表,或者涉及多行记录时,每个事务的操作顺序都要保持一致,降低死锁概率,最好用存储过程固话
6.通过索引等方式优化SQL效率,降低死锁发生概率(减小扫描/锁范围,降低概率)

五.MDL锁

MySQL5.5版本引入了MDL锁(metadata lock),用于解决或者保证DDL操作与DML操作之间的一致性。
在mysqldump的时候不能做DDL操作,会提示waiting for table metadata lock;做DDL操作没办法保护事务,因此引入了meta data lock

session A session B 描述
begin;
select * from t1;
begin;
drop table t1;
被锁住

如果没有MDL锁的保护,那么回话B可以直接执行DDL操作,这样会导致回话A出错。
MySQL5.5 版本引入了MDL锁就是保护这种情况的发生,由于回话A开启了查询,那么获得了MDL锁,锁的模式为SHARED_READ,回话B要执行DDL,则需获得X锁,两者互斥,所以回话B会等待。

MDL锁实在Server中实现。

六.MySQL与锁相关的系统表及视图

6.1 show engine innodb status

测试案例通MDL锁的测试案例

-- 查看InnoDB存储引擎的运行状况
show engine innodb status\G
image.png

6.2 information_schema.innodb_locks

测试案例:

create table t1(id int,name varchar(100));
insert into t1 values (1,'abc'),(2,'def');
session A session B 描述
begin;
update t1 set name = 'ghi' where id = 1;
begin;
update t1 set name = 'ddd' where id = 2;
被锁住了

MySQL 8.0 开始information_schema.innodb_locks 改为 performance_schema.data_locks

mysql> select * from data_locks\G
*************************** 1. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 339873184:1176:300057464
ENGINE_TRANSACTION_ID: 22371
            THREAD_ID: 60
             EVENT_ID: 13
        OBJECT_SCHEMA: test1
          OBJECT_NAME: t1
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: NULL
OBJECT_INSTANCE_BEGIN: 300057464
            LOCK_TYPE: TABLE
            LOCK_MODE: IX
          LOCK_STATUS: GRANTED
            LOCK_DATA: NULL
*************************** 2. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 339873184:118:4:2:300054680
ENGINE_TRANSACTION_ID: 22371
            THREAD_ID: 60
             EVENT_ID: 13
        OBJECT_SCHEMA: test1
          OBJECT_NAME: t1
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: GEN_CLUST_INDEX
OBJECT_INSTANCE_BEGIN: 300054680
            LOCK_TYPE: RECORD
            LOCK_MODE: X
          LOCK_STATUS: WAITING
            LOCK_DATA: 0x00000000C60A
*************************** 3. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 339872336:1176:300052488
ENGINE_TRANSACTION_ID: 22370
            THREAD_ID: 59
             EVENT_ID: 32
        OBJECT_SCHEMA: test1
          OBJECT_NAME: t1
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: NULL
OBJECT_INSTANCE_BEGIN: 300052488
            LOCK_TYPE: TABLE
            LOCK_MODE: IX
          LOCK_STATUS: GRANTED
            LOCK_DATA: NULL
*************************** 4. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 339872336:118:4:1:300049704
ENGINE_TRANSACTION_ID: 22370
            THREAD_ID: 59
             EVENT_ID: 32
        OBJECT_SCHEMA: test1
          OBJECT_NAME: t1
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: GEN_CLUST_INDEX
OBJECT_INSTANCE_BEGIN: 300049704
            LOCK_TYPE: RECORD
            LOCK_MODE: X
          LOCK_STATUS: GRANTED
            LOCK_DATA: supremum pseudo-record
*************************** 5. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 339872336:118:4:2:300049704
ENGINE_TRANSACTION_ID: 22370
            THREAD_ID: 59
             EVENT_ID: 32
        OBJECT_SCHEMA: test1
          OBJECT_NAME: t1
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: GEN_CLUST_INDEX
OBJECT_INSTANCE_BEGIN: 300049704
            LOCK_TYPE: RECORD
            LOCK_MODE: X
          LOCK_STATUS: GRANTED
            LOCK_DATA: 0x00000000C60A
*************************** 6. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 339872336:118:4:3:300049704
ENGINE_TRANSACTION_ID: 22370
            THREAD_ID: 59
             EVENT_ID: 32
        OBJECT_SCHEMA: test1
          OBJECT_NAME: t1
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: GEN_CLUST_INDEX
OBJECT_INSTANCE_BEGIN: 300049704
            LOCK_TYPE: RECORD
            LOCK_MODE: X
          LOCK_STATUS: GRANTED
            LOCK_DATA: 0x00000000C60B
6 rows in set (0.00 sec)

MySQL 8.0之前
information_schema 数据库是mysql自带的,保存着关于MySQL服务器所维护的所有其他数据库的信息。其中innodb_locks表,记录了事务请求但是还没获得的锁,即等待获得的锁。

列名 列描述
lock_id 锁的id,由锁住的空间id编号、页编号、行编号组成
lock_trx_id 锁的事务id。
lock_mode 锁的模式。S[,GAP], X[,GAP], IS[,GAP], IX[,GAP]
lock_type 锁的类型,表锁还是行锁
lock_table 要加锁的表。
lock_index 锁住的索引。
lock_space innodb存储引擎表空间的id号码
lock_page 被锁住的页的数量,如果是表锁,则为null值。
lock_rec 被锁住的行的数量,如果表锁,则为null值。
lock_data 被锁住的行的主键值,如果表锁,则为null值。

MySQL 8.0
Performance_Schema.data_locks

列名 列描述
ENGINE 持有锁或请求锁的存储引擎
ENGINE_LOCK_ID 存储引擎持有锁的id,唯一值,由存储引擎id及锁id组成
ENGINE_TRANSACTION_ID 事务id,INFORMATION_SCHEMA INNODB_TRX 表trx_id
THREAD_ID thread id,Performance Schema threads 表 THREAD_ID
EVENT_ID Performance Schema持有的事件id,thread_id 和event_id 组成
OBJECT_SCHEMA schema名
OBJECT_NAME 表名
PARTITION_NAME 分区表分区名
SUBPARTITION_NAME 子分区表 子分区名
INDEX_NAME 索引名
OBJECT_INSTANCE_BEGIN 内存里锁的地址
LOCK_TYPE 锁的类型,表锁还是行锁
LOCK_MODE 锁的模式。S[,GAP], X[,GAP], IS[,GAP], IX[,GAP], AUTO_INC, and UNKNOWN
LOCK_STATUS 锁状态,GRANTED表示已获取到锁,WAITING表示请求锁中
LOCK_DATA 锁的数据,对于innodb而言,行锁会显示行的地址,其它显示为null

参考文档:

1.https://dev.mysql.com/doc/refman/8.0/en/
2.丁奇45讲
3.https://blog.csdn.net/Saintyyu/article/details/91269087
4.https://zhuanlan.zhihu.com/p/29150809
5.https://www.cnblogs.com/lhdz_bj/p/10522284.html
6.https://www.cnblogs.com/frankyou/p/9582587.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342