Innodb到底是怎么加锁的

本文详细探讨了InnoDB存储引擎的加锁机制,纠正了关于加锁读的常见误解,指出InnoDB不会在全表扫描时加表锁,只会加行级锁。文章从事务锁的概念、加锁的影响因素、加锁流程等方面进行分析,揭示了InnoDB如何通过不同条件判断加锁类型,并通过实例解析了加锁的具体操作,帮助读者深入理解InnoDB的锁机制。
摘要由CSDN通过智能技术生成

学完本文后:妈妈再也不用担心我不知道InnoDB是怎么加锁的了!

流传较广,但是错误的一个观点

不知道从什么时候开始,下边这个错误的观点开始被广泛的流传:

在使用加锁读的方式读取使用InnoDB存储引擎的表时,当在执行查询时没有使用到索引时,行锁会被转换为表锁。

这里强调一点,对于任何INSERTDELETEUPDATESELECT ... LOCK IN SHARE MODESELECT ... FOR UPDATE语句来说,InnoDB存储引擎都不会加表级别的S锁或者X锁(我们这里不讨论表级意向锁的添加),只会加行级锁。所以即使对于全表扫描的加锁读语句来说,也只会对表中的记录进行加锁,而不是直接加一个表锁。

另外,很多小伙伴都会问:“这个语句加什么锁”,其实这是一个伪命题,因为一个语句需要加什么锁受到很多方面的影响,如果有人问你某某语句会加什么锁,那你可以直接回怼:真不专业

我们稍后给大家详细分析一下影响加锁的因素都有哪些,以及从源码的角度看一下InnoDB到底是如何加锁的,希望小伙伴看完后会惊呼:真tm的简单!

不过在进行讨论前我们需要申明一下,我们讨论的只是InnoDB加的事务锁,即为了避免脏写脏读不可重复读幻读这些现象带来的一致性问题而加的锁,并不是为了在多线程访问共享内存区域时而加的锁(比方说两个不同事务所在的线程想读写同一个页面时,需要进行加锁保护),也不包括server层添加的MDL锁。

本文所参考的源码版本为5.7.22

事务锁到底是什么

是一个内存结构,InnoDB中用lock_t这个结构来定义:

image_1fjv1ksadeen1lj6mhb1erl1qc158.png-68kB

不论是行锁,还是表锁都用这个结构来表示。我们给大家画个图:

image_1fjv1nvdh1lr611l41rdp9nmgor5l.png-199.5kB

其中的type_mode是用于区分这个锁结构到底是行锁还是表锁,如果是表锁的话是意向锁、直接对表加锁、还是AUTO-INC锁,如果是行锁的话,具体是正经记录锁、gap锁还是next-key锁。

小贴士:

在InnoDB的实现中,InnoDB的行锁是与记录一一对应的。即使是对于gap锁来说,在实现上也是为某条记录生成一个锁结构,然后该锁结构的类型是gap锁而已,并不是专门为某个区间生成一个锁结构。该gap锁的功能就是每当有别的事务插入记录时,会检查一下待插入记录的下一条记录上是否已经有一个gap锁的锁结构,如果有的话就进入阻塞状态。

我们平时所说的加锁就是在内存中生成这样的一个锁结构(除了生成锁结构,还有一种称作隐式锁的加锁方式,不用生成锁结构)。当然,如果为1条记录加锁就要生成一个锁结构,那岂不是太浪费了!设计InnoDB的大叔提出了一种优化方案,即同一个事务,在同一个页面上加的相同类型的锁都放在同一个锁结构里。

各种类型的锁是如果通过type_mode区分、各种锁都有什么作用,以及如何减少生成锁结构的细节我们这里就不展开了,那又要花费超长的篇幅,大家可以到《MySQL是怎样运行的:从根儿上理解MySQL》书籍中查看,我们下边来看具体的加锁细节。

准备工作

为了故事的顺利发展,我们先创建一个表hero

CREATE TABLE hero (
    number INT,
    name VARCHAR(100),
    country varchar(100),
    PRIMARY KEY (number),
    KEY idx_name (name)
) Engine=InnoDB CHARSET=utf8;
复制代码

然后向这个表里插入几条记录:

INSERT INTO hero VALUES
    (1, 'l刘备', '蜀'),
    (3, 'z诸葛亮', '蜀'),
    (8, 'c曹操', '魏'),
    (15, 'x荀彧', '魏'),
    (20, 's孙权', '吴');
复制代码

然后现在hero表就有了两个索引(一个二级索引,一个聚簇索引),示意图如下:

image_1fjv5sad81rbm18lvqb6mkq9pb7f.png-58.3kB

加锁受哪些因素影响

一条语句加什么锁受多种因素影响,如果你不能确认下边这些因素的时候,最好不要抢先发言说"XXX语句对XXX记录加了什么锁":

  • 事务的隔离级别
  • 语句执行时使用的索引类型(比如聚簇索引、唯一二级索引、普通二级索引)
  • 是否是精确匹配
  • 是否是唯一性搜索
  • 具体执行的语句类型(SELECT、INSERT、DELETE、UPDATE)
  • 是否开启innodb_locks_unsafe_for_binlog系统变量
  • 记录是否被标记删除

这里边有几个概念大家可能不是很清楚,我们先解释一下。

扫描区间

比方说下边这个查询:

SELECT * FROM hero WHERE name <=  'l刘备' AND country &#
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值