1 锁种类
1.1 Record lock
行锁,MySQL的行锁是通过索引加载,要是对应的SQL语句没有走索引,则会全表扫描,行锁无法实现,取而代之的是表锁,此时其它事务无法对当前表进行更新或插入操作。
1.2 GAP lock
间隙锁,锁的就是两个值之间的空隙,因此间隙锁只与往间隙里写入记录这个操作冲突,间隙锁只在隔离级别是可重复读隔离级别下才会生效。
1.3 Next-key lock
Record lock+GAP lock 锁定一个范围,并锁定记录本身,解决幻读。
唯一索引
- 精确等值检索,行锁,不会加GAP锁
- 范围检索,会锁住where条件中相应的范围,范围中的记录以及间隙,可以是两个索引记录之间,也可能是第一个索引记录之前或者最后一个索引之后的空间,两边都是开区间。
- 不走索引检索,全表间隙加gap锁、全表记录加记录锁
非唯一索引
- 精确等值检索,索引记录之前和之后的空间
- 范围检索,会锁住where条件中相应的范围,范围中的记录以及间隙,可以是两个索引记录之间,也可能是第一个索引记录之前或者最后一个索引之后的空间,两边都是开区间。
- 不走索引检索,全表间隙加gap锁、全表记录加记录锁
1.4 S Lock
共享锁:又称读锁,S锁与S锁兼容,可以同时放置。
1.5 X Lock
独占锁:又称排它锁、写锁。X锁不能和其他锁兼容,只要有事务对数据上加了任何锁,其他事务就不能对这些数据再放置X了,同时某个事务放置了X锁之后,其他事务就不能再加其他任何锁了,只有获取排他锁的事务是可以对数据进行读取和修改。
| +代表兼容,-代表不兼容 | X | S |
|---|---|---|
| X | - | - |
| S | - | + |
1.6 意向锁IX、IS
这是为了解决不同粒度的锁的兼容性判断而存在的。
因为锁的粒度不同,表锁的范围覆盖了行锁的范围,所以表锁和行锁会产生冲突,例如事务A对表中某一行数据加了行锁,然后事务B想加表锁,正常来说是应该要冲突的。如果只有行锁的话,要判断是否冲突就得遍历每一行数据了,这样的效率实在不高,因此我们就有了意向表锁。
意向锁的主要目的是为了使得行锁和表锁共存,事务在申请行锁前,必须先申请表的意向锁,成功后再申请行锁。意向锁是表级锁,但是却表示事务正在读或写某一行记录,而不是整个表, 所以意向锁之间不会产生冲突,真正的冲突在加行锁时检查。
意向锁分为意向读锁(IS)和意向写锁(IX)。
| +代表兼容,-代表不兼容 | IS | IX | S | X |
|---|---|---|---|---|
| IS | + | + | + | - |
| IX | + | + | - | - |
| S | + | - | + | - |
| X | - | - | - | - |
2 查看锁等待
SHOW STATUS LIKE 'innodb_row_lock%';
关注点:
- 当前锁等待
Innodb_row_lock_current_waits的值 - 所有锁等待
Innodb_row_lock_waits的值
3 查看等待锁和锁源的信息
3.1 查找出造成锁的连接线程
select * from sys.innodb_lock_waits\G;,找出blocking_pid
[(none)]>select * from sys.innodb_lock_waits\G;
*************************** 1. row ***************************
wait_started: 2021-05-13 15:34:50
wait_age: 00:00:43
wait_age_secs: 43
locked_table: `test`.`t1` #出现锁的表
locked_index: GEN_CLUST_INDEX #出现锁的索引
locked_type: RECORD #锁类型(record、gap、next-key)
waiting_trx_id: 6927 #等待的事务id
waiting_trx_started: 2021-05-13 15:34:50
waiting_trx_age: 00:00:43
waiting_trx_rows_locked: 1
waiting_trx_rows_modified: 0
waiting_pid: 3 #等待的线程id
waiting_query: update t1 set id=8 where id=1 #等待锁的sql语句
waiting_lock_id: 6927:39:3:2
waiting_lock_mode: X #等待锁的类型(X、S)
blocking_trx_id: 6926 #造成锁的事务id
blocking_pid: 2 #造成锁的连接线程
blocking_query: NULL
blocking_lock_id: 6926:39:3:2
blocking_lock_mode: X
blocking_trx_started: 2021-05-13 15:34:15
blocking_trx_age: 00:01:18
blocking_trx_rows_locked: 3
blocking_trx_rows_modified: 1
sql_kill_blocking_query: KILL QUERY 2
sql_kill_blocking_connection: KILL 2
1 row in set, 3 warnings (0.01 sec)
3.2 查找出造成锁的SQL线程
select * from performance_schema.threads where processlist_id=2;,processlist_id为上步找出的blocking_pid,找出THREAD_ID
3.3 查找出当前造成锁的SQL语句
select * from performance_schema.events_statements_current where thread_id=27\G;,thread_id通过上一步找出,SQL_TEXT为具体的SQL语句
3.4 查找出历史造成锁的SQL语句
有时候当前造成锁的语句并不是造成锁的源头,这时候需要查询历史信息,查询锁的源头
select * from performance_schema.events_statements_history where thread_id=27\G;,thread_id通过第2步找出,通过LOCK_TIME和SQL_TEXT进行分析判断
4 死锁监控
show engine innodb status\G;
vim /etc/my.cnf
innodb_print_all_deadlocks=1











网友评论