在 MySQL 事务中,什么时候释放锁?
事务获得锁之后,哪些情况下会释放锁?本期我们聊聊这个主题。
> 作者:操盛春,爱可生技术专家,公众号『一树一溪』作者,专注于研究 MySQL 和 OceanBase 源码。 > >爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
1. 概述
InnoDB 事务执行过程中,加表锁或者行锁之后,释放锁最常见的时机是事务提交或者回滚即将完成时。
因为事务的生命周期结束,它加的锁的生命周期也随之结束。
有一种情况,加锁只是权宜之计,临时为之。如果这种锁也要等到事务提交或者回滚即将完成时才释放,阻塞其它事务的时间也可能更长,这就有点不合理了。所以,这种锁会在事务运行过程中及时释放。
还有一种情况,虽然是在事务提交过程中释放锁,但是并不会等到提交即将完成时才释放,而是在二阶段提交的 prepare 阶段就提前释放。
最后,有点特殊的就是 AUTO-INC 锁了。
2. 不匹配 where 条件
我们先来看看只是权宜之计的加锁场景。
select、update、delete 语句执行过程中,不管 where 条件是否命中索引,也不管是等值查询还是范围查询,只要扫描过的记录,都会加行锁。
> 和 update、delete 不一样,select 只在需要加锁时,才会按照上面的逻辑加锁。
可重复读(REPEATABLE-READ
)、可串行化(SERIALIZABLE
)两种隔离级别,只要加了锁,不管是表锁还是行锁,都要等到事务提交或者回滚即将完成时才释放(手动加的表锁除外)。这就是我们前面说的释放锁最常见的时机了。
读未提交(READ-UNCOMMITTED
)、读已提交(READ-COMMITTED
)两种隔离级别,如果发现记录不匹配 where 条件,会及时释放行锁。这又分为两种情况。
情况 1,如果部分或者全部 where 条件下推到了存储引擎,InnoDB 每读取一条记录,都会判断记录是否匹配下推的 where 条件。
情况 2,server 层每次收到 InnoDB 返回的一条记录,也会判断记录是否匹配 server 层的 where 条件。
以上两种情况,只要记录不匹配 where 条件,就会马上释放当前 SQL 语句对记录加的行锁(其实有个例外情况,稍后介绍)。
这里释放行锁,只会释放不匹配 where 条件的这一条记录上的行锁,过程也比较简单,就是把行锁结构的 bitmap 内存区域中,这条记录对应的位设置为 0。
如果有其它事务正在等待获得这条记录的行锁,还会根据行锁的授予规则,给其它事务授予锁。
前面提到有一个例外情况,现在,该它出场了。
如果事务对某条记录加行锁,没有立即获得锁,而是进入了锁等待状态,等其它事务释放锁之后才获得锁。InnoDB 或者 server 层发现这条记录不匹配 where 条件,并不会释放它的行锁。
这是为什么呢?
因这经过锁等待状态之后才获得的行锁,事务就不知道是哪条 SQL 语句执行时给加的行锁了,所以,即使发现记录不匹配 where 条件,也不会释放它的行锁。
3. prepare 阶段
读未提交(READ-UNCOMMITTED
)、读已提交(READ-COMMITTED
)两种隔离级别下:
- select、update、delete 语句全表扫描、索引范围扫描过程中,只会对索引记录加普通记录锁,不会加间隙锁和 Next-Key 锁。
- 外键约束检查、重复值检查这两个场景下,还是会对索引记录加间隙锁或者 Next-Key 锁的。
这两种隔离级对索引记录前面间隙的锁定,不需要等到事务提交或者回滚即将完成时才释放,在事务二阶段提交的 prepare 阶段就可以提前释放。
Next-Key 锁既锁定索引记录本身,又锁定索引记录前面的间隙。
如果释放索引记录的 Next-Key 锁,就意味着释放了索引记录本身和前面间隙的锁定,这显然是不行的,因为索引记录本身的锁定,要等到事务提交或者回滚即将完成时,才能释放。
那么,Next-Key 锁要怎么释放?
稍安勿躁,我们一起来看。
释放索引记录前面间隙的锁定,需要遍历事务对象的 trx_locks 链表,遍历过程中,每次取一个锁结构(可能是表锁结构或者行锁结构)。
如果锁结构对应的是间隙锁,直接释放索引记录上的间隙锁,主要流程如下:
- 从事务对象的 trx_locks 链表中删除行锁结构。
- 从 rec_hash 的数组中找到锁结构所在的行锁结构链表,然后从链表中删除锁结构。
- 锁结构的 bitmap 内存区域中,可能有一个或者多个位的值为 1,这些位对应的记录都被加了
间隙锁
。如果有其它事务正在等待获得这些记录上的行锁,根据行锁的授予规则,给这些事务授予锁。
如果锁结构对应的是 Next-Key 锁,只释放索引记录前面间隙的锁定,保留索引记录本身的锁定,主要流程如下:
- 给锁结构的 type_mode 属性加上
LOCK_REC_NOT_GAP
标志,也就是直接把 Next-Key 锁变成了普通记录锁。 - 锁结构的 bitmap 内存区域中,可能有一个或者多个位的值为 1,这些位对应的记录都被加了
Next-Key 锁
,现在都变成了普通记录锁
。如果有其它事务想往这些记录前面的间隙插入记录被阻塞了,现在就可以根据行锁的授予规则,给这些事务授予插入意向锁了。
4. 事务提交或回滚
事务加行锁的共享锁、排他锁之前,会分别加表级别的意向共享锁、意向排他锁,这两种表锁都要到事务提交或者回滚即将完成时才释放。
事物加的所有行锁,除了读未提交(READ-UNCOMMITTED
)、读已提交(READ-COMMITTED
)两种隔离级别已经释放的不匹配 where 条件的记录上的行锁、索引记录前面间隙的锁定之外,剩下的行锁,都要等到事务提交或者回滚即将完成时才释放。
事务提交或者回滚事务即将完成时,释放表锁和行锁需要遍历 trx_locks 链表,遍历过程中,每次取一个锁结构。
对于行锁结构,释放锁的主要流程如下:
- 从事务对象的 trx_locks 链表中删除行锁结构。
- 从 rec_hash 的数组中找到锁结构所在的行锁结构链表,然后从链表中删除行锁结构。
- 锁结构的 bitmap 内存区域中,可能有一个或者多个位的值为 1,这些位对应的记录都被加了某种行锁。如果有其它事务正在等待获得这些记录上的行锁,根据行锁的授予规则,给这些事务授予锁。
对于表锁结构,释放锁的主要流程如下:
- 从事务对象的 trx_locks 链表中删除表锁结构。
- 从表对象的 locks 链表删除表锁结构。
- 如果有其它事务正在等待获得这个表的表锁,根据表锁的授予规则,给这些事务授予锁。
5. AUTO-INC 锁
把 AUTO-INC 锁单独拿出来说,是因为它有点特殊。
前面介绍 InnoDB 表锁时,我们介绍过,AUTO-INC 锁有两种类型,一种是轻量锁,这其实只是个互斥量。
另一种才是真正的表级别的 AUTO-INC 锁,它会创建表锁结构,和表级别的意向共享锁、意向排他锁一样,都属于表锁。
AUTO-INC 锁的这两种类型,释放时机不同。
轻量锁,用完就释放,也就是 insert 或者 update 语句获取到自增列的自增值之后,就可以释放了。
因为这种类型,只是个互斥量,释放也很简单,调用释放互斥量的方法就可以了。
此时,可能有其它事务正在等待获得这个表的轻量 AUTO-INC 锁,也就是等待获得这个互斥量,由操作系统决定哪个事务能获得这个互斥量。
真正的表级别的 AUTO-INC 锁,要等到加锁的 SQL 语句执行完成才释放,主要流程如下:
- 从事务对象的 autoinc_locks 数组中删除表锁结构。
- 从事务对象的 trx_locks 链表中删除表锁结构。
- 从表对象的 locks 链表中删除表锁结构。
- 如果有其它事务正在等待获得这个表的
AUTO-INC 锁
,根据表锁的授予规则,给这些事务授予锁。
6. 总结
事务执行过程中加的表锁,都要等到提交或者回滚即将完成时才释放(手动加的表锁除外)。
事务执行过程中加的行锁,根据事务隔离级别的不同,释放时机不同。
可重复读(REPEATABLE-READ
)、可串行化(SERIALIZABLE
)两种隔离级别,事务加的所有行锁,都要等到提交或者回滚即将完成时才释放。
读未提交(READ-UNCOMMITTED
)、读已提交(READ-COMMITTED
)两种隔离级别,事务加的行锁,释放时机不同。
- 对于不匹配 where 条件的记录,发现不匹配之后,server 层或者 InnoDB 就会释放这些记录的行锁。
- 对于间隙锁或者 Next-Key 锁,在二阶段提交的 prepare 阶段,会释放记录前面间隙的锁定,保留记录本身的锁定。
- 剩余未释放的行锁,都要等到事务提交或者回滚即将完成时才释放。
AUTO-INC 锁有两种类型,对应两种释放时机:
- 轻量锁,用完就释放。
- 真正的表级别的 AUTO-INC 锁,加锁的 SQL 语句执行完成时释放。
更多技术文章,请访问:https://opensource.actionsky.com/
关于 SQLE
SQLE 是一款全方位的 SQL 质量管理平台,覆盖开发至生产环境的 SQL 审核和管理。支持主流的开源、商业、国产数据库,为开发和运维提供流程自动化能力,提升上线效率,提高数据质量。
✨ Github:https://github.com/actiontech/sqle
📚 文档:https://actiontech.github.io/sqle-docs/
💻 官网:https://opensource.actionsky.com/sqle/
👥 微信群:请添加小助手加入 ActionOpenSource

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Embedding空间中的时序异常检测
作者 | StarKeeper 导读 本文深入探讨了如何在Embedding空间中运用先进的时序异常检测技术,针对安全、反作弊等业务场景下的流量与用户行为进行精准监控。通过向量化处理和Embedding技术,将多维度的业务数据映射至高维空间,并基于此空间中的样本分布特征进行异常检测。实验验证了该方法在不同异常类型下的有效性,为快速定位和处理异常提供了有力支持。同时,文章还讨论了算法在实际应用中的调整与优化方向,展望了未来在异常检测领域的进一步应用与发展。 全文5887字,预计阅读时间15分钟。 01 背景 在安全、反作弊等业务场景下,对流量、用户行为进行异常检测是基本的刚需。通常的做法是,在各个业务维度上,对流量、用户行为进行统计分析,提取出相应的指标特征,然后在时间维度上,对这些指标特征进行建模分析。再利用相关的算法来检测当前的指标值是否背离了该指标在历史数据中的分布规律。 02 示例 假设某业务场景下,用户有100个来源渠道,用户使用产品时,有10种不同的操作方式,对于用户的行为,我们可以简单的撮取出PV、UV、失败率等指标。那么我们可以建立这样一个监控: 监控的维度:来源渠道 *...
- 下一篇
AI新玩法!阿里云联合优酷跨界打造Create@AI江湖创作大赛
随着网剧《少年白马醉春风》的热播,许多人心中的江湖梦被唤醒,渴望踏入那个充满传奇色彩的影视世界,体验一段属于自己的江湖之旅。 在 AIGC 技术日益成熟的今天,这一梦想变得触手可及。 阿里云携手优酷,发起了Create@AI江湖创作大赛,将网剧《少年白马醉春风》这一热门影视 IP 与阿里云的 AI 技术相结合,利用阿里云函数计算的强大技术支持,为AI创作的开发和部署提供源源不断的算力和专业指导。 参与此次赛事,你可以借助 AI 的技术和工具,绘制出自己心中的江湖画卷,参赛获奖作品有机会做成官方授权正版周边进行发售,更有机会获得最高 50000 元的现金奖励。 此次赛事由阿里云联合优酷共同发起,作为“创客北京”专项赛,赛事面向全社会开放,欢迎 AI 相关中小企业、创新团队、影视制作相关团队、数字艺术创作者以及对 AIGC 感兴趣的用户参与。 访问链接可即刻开启创作:https://developer.aliyun.com/plan/create/snbm 影视与科技的交汇点:阿里云函数计算的 AI 技术引领双领域创新 在当下的文娱市场中,江湖题材的 IP 正以其独特的魅力和广泛的受众基础...
相关文章
文章评论
共有0条评论来说两句吧...