MySQL InnoDB 共享读锁与排他写锁

锁列表

  • 共享与列排他锁
  • 意向锁
  • 记录锁
  • 间隙锁
  • Next-Key锁
  • 插入意向锁
  • AUTO-INC锁

这次我们只来讨论和实验共享和排他锁。

共享与排他锁

共享和排他锁也可以称为共享读锁和排他写锁,分别用大写字母S和X表示,S和X分别对应为shared(S) locks 和exclusive(X) locks。

  • 共享锁允许事务持有进行读行
  • 排他锁允许事务持有该锁进行更新或删除行

共享读锁允许多个事务持有,排他写锁只允许一个事务持有。
如果一个事务持有排他写锁,那么其他事务就只有等待持有该锁的事务释放锁,如果事务等待锁时间过长,等待锁的事务就会被回滚。
例如:两个事务同时对同一行进行数据更新:
事务A:

begin;
update sys_user set name_pinyin='wangwu1' where id=17;

事务B:

begin;
update sys_user set name_pinyin='wangwu1' where id=17;

如果事务A先执行update语句,那么事务A先获取到id=17行的排他写锁,此时如果事务B执行update语句,事务B就只有等待事务A释放锁。如果事务A没有在事务B等待锁超时之前释放锁的话,那么事务B就会回滚,如下图:
事务B被回滚:
MySQL InnoDB 共享读锁与排他写锁

在事务B等待锁的过程中,我们使用以下SQL查询锁情况:


SELECT r.trx_id AS waiting_trx_id, r.trx_mysql_thread_id AS waiting_thread, LEFT(r.trx_query, 20) AS waiting_query
 , concat(concat(lw.lock_type, ' '), lw.lock_mode) AS waiting_for_lock
 , b.trx_id AS blocking_trx_id, b.trx_mysql_thread_id AS blocking_thread, LEFT(b.trx_query, 20) AS blocking_query
 , concat(concat(lb.lock_type, ' '), lb.lock_mode) AS blocking_lock
FROM performance_schema.data_lock_waits w
 INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.BLOCKING_ENGINE_TRANSACTION_ID
 INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.REQUESTING_ENGINE_TRANSACTION_ID
 INNER JOIN performance_schema.data_locks lw ON lw.ENGINE_TRANSACTION_ID = r.trx_id
 INNER JOIN performance_schema.data_locks lb ON lb.ENGINE_TRANSACTION_ID = b.trx_id;

得到如下输出:

使用show engine innodb status输出如下:

show engine innodb status;
---TRANSACTION 126422095, ACTIVE 39 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 28, OS thread handle 139734349227776, query id 26244 192.168.1.83 root updating
update sys_user set name_pinyin='wangwu1' where id=17
------- TRX HAS BEEN WAITING 39 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 484 page no 7 n bits 328 index PRIMARY of table `employees`.`sys_user` trx id 126422095 lock_mode X locks rec but not gap waiting
Record lock, heap no 257
------------------

注意

  1. Innodb在可重复读的事务隔离级别下使用MVCC下对SELECT是不加锁的。

参考

  1. https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html
  2. https://help.aliyun.com/document_detail/205071.html
上一篇:HeadFirst设计模式学习笔记(C#版):鸭子与策略(Strategy)模式


下一篇:MySQL-优化INSERT、UPDATE和DELETE