写点什么

MySQL 探秘 (五):InnoDB 锁的类型和状态查询

  • 2021 年 12 月 05 日
  • 本文字数:1851 字

    阅读完需:约 6 分钟

MySQL探秘(五):InnoDB锁的类型和状态查询

备注:公众号原名张狗蛋的技术之路,现已改名为程序员历小冰

锁是数据库系统区分于文件系统的一个关键特性。数据库使用锁来支持对共享资源进行并发访问,提供数据的完整性和一致性。此外,数据库事务的隔离性也是通过锁实现的。InnoDB 在此方面一直优于其他数据库引擎。InnoDB 会在行级别上对表数据上锁,而 MyISAM 只能在表级别上锁,二者性能差异可想而知。

InnoDB 存储引擎中的锁

 InnoDB 存储引擎实现了如下两种标准的行级锁:

  • 共享锁(S Lock),允许事务读取一行

  • 排他锁(X Lock),允许事务删除或更新一行数据

  如果一个事务 T1 已经获取了行 r 的共享锁,那么另外一个事务 T2 可以立刻获得行 r 的共享锁,因为读取并不会改变数据,可以进行并发的读取操作;但若其他的事务 T3 想要获取行 r 的排他锁,则必须等待事务 T1 和 T2 释放行 r 上的共享锁之后才能继续,因为获取排他锁一般是为了改变数据,所以不能同时进行读取或则其他写入操作。

 InnoDB 存储引擎支持多粒度锁定,这种锁定允许事务在行级上的锁和表级上的锁同时存在。为了支持在不同粒度上进行加锁操作,InnoDB 存储引擎支持一种称为意向锁的锁方式。意向锁是将锁定的对象分为多个层次,意向锁意味着事务希望在更细粒度上进行加锁。

 InnoDB 存储引擎的意向锁即为表级别的锁。设计目的主要是为了在一个事务中揭示下一行将被请求的锁类型。其支持两种意向锁:

  • 意向共享锁(IS Lock),事务想要获得一张表中某几行的共享锁

  • 意向排他锁(IX Lock),事务想要获得一张表中某几行的排他锁

 需要注意的是意向锁是表级别的锁,它不会和行级的 X,S 锁发生冲突。只会和表级的 X,S 发生冲突。故表级别的意向锁和表级别的锁的兼容性如下表所示


 向一个表添加表级 X 锁的时候(执行 ALTER TABLE, DROP TABLE, LOCK TABLES 等操作),如果没有意向锁的话,则需要遍历所有整个表判断是否有行锁的存在,以免发生冲突。如果有了意向锁,只需要判断该意向锁与即将添加的表级锁是否兼容即可。因为意向锁的存在代表了,有行级锁的存在或者即将有行级锁的存在,因而无需遍历整个表,即可获取结果。


 如果将上锁的对象看成一棵树,那么对最下层的对象上锁,也就是对最细粒度的对象进行上锁,那么首先需要对粗粒度的对象上锁。如上图所示,如果需要对表 1 的记录 m 行上 X 锁,那么需要先对表 1 加意向 IX 锁,然后对记录 m 上 X 锁。如果其中任何一个部分导致等待,那么该操作需要等待粗粒度锁的完成。

InnoDB 锁相关状态查询

 用户可以使用 INFOMATION_SCHEMA 库下的 INNODB_TRX、INNODB_LOCKS 和 INNODB_LOCK_WAITS 表来监控当前事务并分析可能出现的锁问题。INNODB_TRX 的定义如下表所示,其由 8 个字段组成。



mysql> SELECT * FROM information_schema.INNODB_TRX\G;************************************* 1.row *********************************************trx_id:  7311F4trx_state: LOCK WAITtrx_started: 2010-01-04 10:49:33trx_requested_lock_id: 7311F4:96:3:2trx_wait_started: 2010-01-04 10:49:33trx_weight: 2trx_mysql_thread_id: 471719trx_query: select * from parent lock in share mode
复制代码

 INNODB_TRX 表只能显示当前运行的 InnoDB 事务,并不能直接判断锁的一些情况。如果需要查看锁,则还需要访问表 INNODB_LOCKS,该表的字段组成如下表所示。



mysql> SELECT * FROM information_schema.INNODB_LOCKS\G;*************************************** 1.row *************************************lock_id: 7311F4:96:3:2lock_trx_id: 7311F4lock_mode: Slock_type: RECORDlock_type: 'mytest'.'parent'lock_index: 'PRIMARY'lock_space: 96lock_page: 3lock_rec: 2lock_data: 1
复制代码

 通过表 INNODB_LOCKS 查看每张表上锁的情况后,用户就可以来判断由此引发的等待情况。当时当事务量非常大,其中锁和等待也时常发生,这个时候就不那么容易判断。但是通过表 INNODB_LOCK_WAITS,可以很直观的反应当前事务的等待。表 INNODB_LOCK_WAITS 由四个字段组成,如下表所示。



mysql> SELECT * FROM information_schema.INNODB_LOCK_WAITS\G;*******************************************1.row************************************requesting_trx_id: 7311F4requesting_lock_id: 7311F4:96:3:2blocking_trx_id: 730FEEblocking_lock_id: 730FEE:96:3:2
复制代码

 通过上述的 SQL 语句,用户可以清楚直观地看到哪个事务阻塞了另一个事务,然后使用上述的事务 ID 和锁 ID,去 INNODB_TRX 和 INNDOB_LOCKS 表中查看更加详细的信息。

后记

 我们后续还会学习 InnoDB 的一致性非锁定读相关的知识,请大家持续关注。

发布于: 2 小时前阅读数: 6
用户头像

程序员历小冰 2018.04.28 加入

历小冰的技术博客,专注于探讨后端生态的点点滴滴,内容包括微服务、分布式、数据库、性能调优和各类源码分析。

评论

发布
暂无评论
MySQL探秘(五):InnoDB锁的类型和状态查询