技本功丨浅谈MySQL的七种锁

2024-06-14 20:18

本文主要是介绍技本功丨浅谈MySQL的七种锁,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

作者:宋丹琪(花名:三思)袋鼠云云服务部DBA团队 数据库工程师

时常会有开发的同学突然紧张兮兮地找我,

然后丢给我一个代码层面的

CannotAcquireLockException的报错,

一脸无辜地问我是不是自己搞出了一个死锁。

好像大家看到LOCK的字眼

总会第一时间想到死锁而忽略了锁,

难道我们锁没有面子的嘛,

我们锁的大家族可足足有七种呢?

那么到底什么是锁,有哪些锁,

请听我娓娓道来。。

01 共享锁(S锁)和排它锁(X锁)

事务拿到某一行记录的共享S锁,才可以读取这一行,并阻止别的事物对其添加X锁

事务拿到某一行记录的排它X锁,才可以修改或者删除这一行

共享锁的目的是提高读读并发

排他锁的目的是为了保证数据的一致性

02 意向锁

1)意向共享锁

预示事务有意向对表中的某些行加共享S锁

2)意向排他锁

预示着事务有意向对表中的某些行加排他X锁

3) IS、S、IX、X锁之间的兼容性比较

4)意向锁的意义在哪里?

1.IX,IS是表级锁,不会和行级的X,S锁发生冲突。只会和表级的X,S发生冲突

2.意向锁是在添加行锁之前添加。

3.如果没有意向锁,当向一个表添加表级X锁时,就需要遍历整张表来判断是否存行锁,以免发生冲突

4.如果有了意向锁,只需要判断该意向锁与表级锁是否兼容即可。

03 插入意向锁(insert intention looks)

插入意向锁是间隙锁的一种,针对insert操作产生。

目的是提高插入并发。

多个事物,在同一个索引,同一个范围区间进行插入记录的时候,如果 插入的位置不冲突,不会阻塞彼此。

示例:

由于事物一和事物二都是对表的同一索引范围进行insert,使用的插入意向锁,由于插入的记录并不冲突,所以并不会阻塞事物二。如果事物二插入的记录与事物一冲突,会被X锁阻塞。

04 记录锁

对单条索引记录进行加锁,锁住的是索引记录而非记录本身,即使表中没有任何索引,MySQL会自动创建一个隐式的row_id作为聚集索引来进行加锁。

05 间隙锁(gap锁)

封锁记录中的间隔,防止间隔中被其他事务插入。

间隙锁主要出现在RR隔离级别,避免出现幻读。

MVCC(多版本并发)

1.MVCC的作用

避免脏读、写不阻塞读、实现可重复读、多版本控制

2.在MVCC下,读操作可以分为两种:快照读、当前读

1)快照读

select * from tbl_name where ...

2)当前读

select * from tbl_name where ... for update;

update

delete

insert

3)为什么delete/update也是一种当前读?(如一个update操作)

a.在进行update的时候,MySQL会根据where条件得到过滤出来的第一条记录,并进行加锁(currenet read)

b.对该条记录进行update

c.再次读取下一条记录,直到没有满足条件的记录为止

d.delete原理与之类似

4)为什么insert也是一种当前读?

insert操作可能会触发Unique Key的冲突检查,也会进行一个当前读。

隔离级别

1.Read Uncommitted

可以读取到未提交的事物。

2.Rrad Committed(RC)

针对当前读,RC隔离级别保证对读取到的记录加锁 (记录锁),存在幻读现象。

3.Repeatable Read (RR)

针对当前读,RR隔离级别保证对读取到的记录加锁 (记录锁),同时保证对读取的范围加锁,新的满足查询条件的记录不能够插入 (间隙锁),不存在幻读现象。

4.Serializable

所有的读操作均为当前读,读加读锁 (S锁),写加写锁 (X锁)。

读写冲突,并发行很差。

几种触发间隙锁的情况

1.id非唯一索引+RR

SQL:delete from t1 where id = 10;

加锁流程如下:

a.通过id索引定位到第一条满足查询条件的记录,加记录上的X锁,加GAP上的GAP锁,

b.然后加主键聚簇索引上的记录X锁,然后返回;

c.然后读取下一条,重复进行。

d.直至进行到第一条不满足条件的记录[11,f],此时,不需要加记录X锁,但是仍旧需要加GAP锁,最后返回结束。

2.id无索引+RR

SQL:delete from t1 where id = 10;

a.由于id字段无索引,进行全表扫描的当前读,

b.聚簇索引上的所有记录,都被加上了X锁。其次,聚簇索引每条记录间的间隙都被加上了GAP锁。

3.针对id无索引+RR MySQL性能上做的一些优化

semi-consistent read

semi-consistent read开启的情况下,对于不满足查询条件的记录,MySQL会提前放锁。

针对上面的这个用例,就是除了记录[d,10],[g,10]之外,所有的记录锁都会被释放,同时不加GAP锁。

4.semi-consistent read如何触发?

1)隔离级别是read committed;

2)隔离级别是Repeatable Read,同时设置了innodb_locks_unsafe_for_binlog 参数。

示例一

 

示例二

 

示例三

 

06 临键锁(Next-Key Locks)

临键锁是记录锁和间隙锁的组合,既锁住了记录也锁住了范围。

临键锁的主要目的,也是为了避免幻读。

如果把事务的隔离级别降级为RC,临键锁就也会失效。

通常情况下,InnoDB在搜索或扫描索引的行锁机制中使用“临键锁(next-key locking)”算法来锁定某索引记录及其前部的间隙(gap),以阻塞其它用户紧跟在该索引记录之前插入其它索引记录。

innodb_locks_unsafe_for_binlog默认为OFF,意为禁止使用非安全锁,也即启用间隙锁功能。将其设定为ON表示禁止锁定索引记录前的间隙,也即禁用间隙锁,InnoDB仅使用索引记录锁(index-record lock)进行索引搜索或扫描,不过,这并不禁止InnoDB在执行外键约束检查或重复键检查时使用间隙锁。

innodb_locks_unsafe_for_binlog的效果:

(1)对UPDATE或DELETE语句来说,InnoDB仅锁定需要更新或删除的行,对不能够被WHERE条件匹配的行施加的锁会在条件检查后予以释放。这可以有效地降低死锁出现的概率;

(2)执行UPDATE语句时,如果某行已经被其它语句锁定,InnoDB会启动一个“半一致性(semi-consistent)”读操作从MySQL最近一次提交版本中获得此行,并以之判定其是否能够并当前UPDATE的WHERE条件所匹配。如果能够匹配,MySQL会再次对其进行锁定,而如果仍有其它锁存在,则需要先等待它们退出。

(3)innodb_locks_unsafe_for_binlog可能会造成幻读

示例一

innodb_locks_unsafe_for_binlog=off的情况下:

 

示例二

innodb_locks_unsafe_for_binlog=on的情况下:

 

查看binlog日志:

因此,当innodb_locks_unsafe_for_binlog=on的情况下,会让你容易造成数据的不一致。

07 自增长锁

自增长锁是一种表级锁,专门针对auto_increment类型的列。

自增长列锁各模式分析:

innodb_autoinc_lock_mode:自增长长锁模式

0:

不管是insert into values (simple insert)还是insert into select (bulk insert),都是:持有锁、读取/修改、执行SQL、释放,不需要等到事务提交就释放锁,但是需要SQL执行完成,并且不能保证连续。

持有latch ---> 读取和修改auto锁 ---> 执行insert ---> 释放

注意:不需要等待insert所在的事务是否提交

缺点:可能出现数字不连续

持有时间相对过长:SQL执行完毕,不需要事务提交

1:

默认值,对于回滚是不能保证自增长列连续的。

对于simple insert (insert into values):持有锁、读取、释放、执行SQL,最快,不需要执行完SQL就释放,不需要等待insert执行完毕就可以释放锁。

对于bulk insert (insert into select):持有锁、读取、执行SQL、释放,需要执行完SQL才释放。(对于批量insert来说等同于0)

优点:

对于simple insert 来说,性能比0好些,对于批量来说,性能等同于0

缺点:

数字不连续

对于批量来说持有锁的时间相对过长

2:

经常改为2,主要是为了唯一,不是为了连续,在批量insert时或者批量insert并发的时候用

优点:速度最快

缺点:只能保证唯一,不能保证递增和连续。持有、读取和修改、释放、执行SQL

建议修改成2,对于批量的insert可以提升性能

示例

 

由于innodb_autoinc_lock_mode=1,所以事物一并不会阻塞事物二的simple insert,保证了id字段的唯一性。

参考引用:

何登成的技术博客——《MySQL 加锁处理分析》

微信公众号:架构师之路

 

这篇关于技本功丨浅谈MySQL的七种锁的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1061412

相关文章

MySQL中EXISTS与IN用法使用与对比分析

《MySQL中EXISTS与IN用法使用与对比分析》在MySQL中,EXISTS和IN都用于子查询中根据另一个查询的结果来过滤主查询的记录,本文将基于工作原理、效率和应用场景进行全面对比... 目录一、基本用法详解1. IN 运算符2. EXISTS 运算符二、EXISTS 与 IN 的选择策略三、性能对比

MySQL常用字符串函数示例和场景介绍

《MySQL常用字符串函数示例和场景介绍》MySQL提供了丰富的字符串函数帮助我们高效地对字符串进行处理、转换和分析,本文我将全面且深入地介绍MySQL常用的字符串函数,并结合具体示例和场景,帮你熟练... 目录一、字符串函数概述1.1 字符串函数的作用1.2 字符串函数分类二、字符串长度与统计函数2.1

SQL Server跟踪自动统计信息更新实战指南

《SQLServer跟踪自动统计信息更新实战指南》本文详解SQLServer自动统计信息更新的跟踪方法,推荐使用扩展事件实时捕获更新操作及详细信息,同时结合系统视图快速检查统计信息状态,重点强调修... 目录SQL Server 如何跟踪自动统计信息更新:深入解析与实战指南 核心跟踪方法1️⃣ 利用系统目录

MySQL 内存使用率常用分析语句

《MySQL内存使用率常用分析语句》用户整理了MySQL内存占用过高的分析方法,涵盖操作系统层确认及数据库层bufferpool、内存模块差值、线程状态、performance_schema性能数据... 目录一、 OS层二、 DB层1. 全局情况2. 内存占js用详情最近连续遇到mysql内存占用过高导致

Mysql中设计数据表的过程解析

《Mysql中设计数据表的过程解析》数据库约束通过NOTNULL、UNIQUE、DEFAULT、主键和外键等规则保障数据完整性,自动校验数据,减少人工错误,提升数据一致性和业务逻辑严谨性,本文介绍My... 目录1.引言2.NOT NULL——制定某列不可以存储NULL值2.UNIQUE——保证某一列的每一

解密SQL查询语句执行的过程

《解密SQL查询语句执行的过程》文章讲解了SQL语句的执行流程,涵盖解析、优化、执行三个核心阶段,并介绍执行计划查看方法EXPLAIN,同时提出性能优化技巧如合理使用索引、避免SELECT*、JOIN... 目录1. SQL语句的基本结构2. SQL语句的执行过程3. SQL语句的执行计划4. 常见的性能优

SQL Server 中的 WITH (NOLOCK) 示例详解

《SQLServer中的WITH(NOLOCK)示例详解》SQLServer中的WITH(NOLOCK)是一种表提示,等同于READUNCOMMITTED隔离级别,允许查询在不获取共享锁的情... 目录SQL Server 中的 WITH (NOLOCK) 详解一、WITH (NOLOCK) 的本质二、工作

MySQL 强制使用特定索引的操作

《MySQL强制使用特定索引的操作》MySQL可通过FORCEINDEX、USEINDEX等语法强制查询使用特定索引,但优化器可能不采纳,需结合EXPLAIN分析执行计划,避免性能下降,注意版本差异... 目录1. 使用FORCE INDEX语法2. 使用USE INDEX语法3. 使用IGNORE IND

SQL Server安装时候没有中文选项的解决方法

《SQLServer安装时候没有中文选项的解决方法》用户安装SQLServer时界面全英文,无中文选项,通过修改安装设置中的国家或地区为中文中国,重启安装程序后界面恢复中文,解决了问题,对SQLSe... 你是不是在安装SQL Server时候发现安装界面和别人不同,并且无论如何都没有中文选项?这个问题也

2025版mysql8.0.41 winx64 手动安装详细教程

《2025版mysql8.0.41winx64手动安装详细教程》本文指导Windows系统下MySQL安装配置,包含解压、设置环境变量、my.ini配置、初始化密码获取、服务安装与手动启动等步骤,... 目录一、下载安装包二、配置环境变量三、安装配置四、启动 mysql 服务,修改密码一、下载安装包安装地