共计 3566 个字符,预计需要花费 9 分钟才能阅读完成。
自动写代码机器人,免费开通
这篇文章主要介绍 MySQL 锁机制的详细分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
文章目录
锁
锁分类
共享锁(读锁,读写互斥,读读互不影响)
排他锁(写锁,独占锁)
共享锁和排他锁的区别
表锁
为什么需要加入意向锁
意向锁:意向共享锁和意向排他锁
单个表锁定
全局表锁定
行锁
行锁升级为表锁(行锁实际是给索引加锁,如果没用索引而全表扫描,则会给全表加锁)
修改、删除某一行记录,且未提交事务时,该行会一直被行锁锁定
记录锁
间隙锁(Gap Locks)
间隙锁的作用:防止幻读
innodb 自动使用间隙锁的条件
间隙锁锁定的区域
next-key 锁【临键锁】
记录锁、间隙锁、临间锁的区别
锁
锁是计算机协调多个线程访问同一共享资源的机制,主要用于解决多线程访问同一共享资源的并发安全问题。
锁分类
(1)从性能分为:乐观锁和悲观锁
MySQL 中采用版本号控制,JVM 中使用 CAS
(2)从数据库操作类型分为:读锁(共享锁)、写锁(排他锁)【读锁和写锁都属于悲观锁】
读锁(共享锁 ):针对相同行记录,多个读操作可以同时进行,但任何事务都不能进行
写锁(排他锁 ):获取排他锁的事务既能读数据,又能修改数据。获取到写锁的事务为完成之前,会阻塞其他事务获取写锁或读锁。
(3)从颗粒度划分为,表锁和行锁
注意:
(1)读锁、写锁都属于行级锁,即事务 1 对商品 A 获取写锁,和事务 2 对商品 B 获取写锁互相不会阻塞的。
(2)如果 sql 语句使用了行锁,当 SQL 未使用索引而使用全表扫描的时候,行级锁会变成表锁。
(3)锁只有在执行 commit 或者 rollback 的时候才会释放,并且所有的锁都是在同一时刻被释放。
(4)Innodb 引擎执行普通的修改、删除 sql 语句时,会给修改和删除的行加行锁。
共享锁(读锁,读写互斥,读读互不影响)
事务 A 使用共享锁获取了某条(或某些)记录时,事务 B 可以读取这些记录,可以继续添加共享锁,但是不能修改这些记录(当事务 C 对这些数据修改或删除时,会进入阻塞状态,直至锁等待超时或者事务 A 提交)
如何使用共享锁和释放共享锁
# 加锁 SELECT ... LOCK IN SHARE MODE# 释放锁 commit;rollback;
作用
SELECT … LOCK IN SHARE MODE 在读取的若干行记录加共享锁(share lock),其他事务只能对这些行查询而不能修改这些记录。多个事务可以对相同的行记录加共享锁,因此获取了共享锁的事务不一定能修改行数据
使用场景:读取结果集的最新版本,同时防止其他事务产生更新该结果集
例如:并发下对商品库存的操作
排他锁(写锁,独占锁)
select … for update 在对读取的行记录加排他锁,只允许获取到该排他锁的事务修改该行记录,防止其他事务对该行进行修改,就像普通的 update 语句执行时会加行锁一样。
如何使用排他锁
# 加排他锁 select ... for update // 排他锁 # 释放锁 commit;rollback;
共享锁和排他锁的区别
(1)一旦某个事务获取了排他锁,其他事务就无法再获取排他锁。
多个事务可以对相同行数据加共享锁。
(2)给指定行加了共享锁的事务,不一定能修改该行数据,因为其他事务也可能对该行加了共享锁或排他锁;给指定行加了排他锁的事务,则可以修改加了排他锁的该行数据
表锁
使用表级锁定的主要是 MyISAM,MEMORY,CSV 等一些非事务性存储引擎。
表锁一般在数据迁移时使用。
意向锁:意向共享锁和意向排他锁
某行加共享锁的前提是:该行数据所在表会先获取到意向共享锁。
某行加排他锁的前提是:该行数据所在表会先获取到意向排他锁。
注意:意向共享锁和意向排他锁均是表锁,无法手动创建。
为什么需要加入意向锁
意向锁是为了告知 mysql 该表已经存在数据被加锁,而不需要逐行扫描是否加锁,提搞加锁的效率。
单个表锁定
lock tables saas.goods read,saas.account write; // 给 saas 库中的 goods 表加读锁,account 表加写锁 unlock tables; // 解锁
全局表锁定
FLUSH TABLES WITH READ LOCK; // 所有库所有表都被锁定只读 unlock tables; // 解锁
注意:在客户端和数据库断开连接时,都会隐式的执行 unlock tables。如果要让表锁定生效就必须一直保持连接。
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高;
行锁
行锁是锁一行或者多行记录
MySQL 的行锁是基于索引,行锁是加在索引上,而不是加在行记录上的。
如上图所示,数据库中有 1 个主键索引和 1 个普通索引,图中的 sql 语句是基于普通索引查询,命中 4 条记录,此时一把行锁就锁定两条记录,而其他事务修改这两条记录中的任意一条,都会一直阻塞【获取锁的事务没有执行 commit 之前】,下图就是上图没有执行 commit 语句时的情况。
行锁升级为表锁(行锁实际是给索引加锁,如果没用索引而全表扫描,则会给全表加锁)
上图中 where 条件中,虽然 template_name 建立普通索引,但使用 or 关键字,导致 template_name 的索引失效,从而进行了全表扫描,锁定了整张表。
修改、删除某一行记录,且未提交事务时,该行会一直被行锁锁定
窗口 1 中删除某一行,但没有提交。窗口 2 中更新该行会一直处于阻塞中。
记录锁
行锁:行锁是命中索引,一把锁锁的是一张表的一条记录或多条记录
记录锁:记录锁是在行锁的衍生锁,记录锁锁的是表中的某一条记录,记录锁出现的条件必须是:精确命中索引,且索引是唯一索引(比如主键 id、唯一索引列)。
间隙锁(Gap Locks)
经典参考文章
间隙锁的作用:防止幻读
间隙锁的目的是为了防止幻读,其主要通过两个方面实现这个目的:
(1)防止止间隙内有新数据被插入
(2)防止范围内已存在的数据被更新
innodb 自动使用间隙锁的条件
(1)数据隔离级别必须为可重复读
(2)检索条件必须使用索引(没有使用索引的话,mysql 会全表扫描,那样会锁定整张表所有的记录,包括不存在的记录,此时其他事务不能修改不能删除不能添加)
间隙锁锁定的区域
根据检索条件向左寻找最靠近检索条件的记录值 A,作为左区间,向右寻找最靠近检索条件的记录值 B 作为右区间,即锁定的间隙为(A,B)。下图中,where number= 5 的话,那么间隙锁的区间范围为 [4,11];
session 1:start transaction ; 触发间隙锁的方式 1:select * from news where number=4 for update ;
触发间隙锁的方式 2:update news set number=3 where number=4; session 2:start transaction ;insert into news value(2,4);#(阻塞)insert into news value(2,2);#(阻塞)insert into news value(4,4);#(阻塞)insert into news value(4,5);#(阻塞)insert into news value(7,5);#(执行成功)insert into news value(9,5);#(执行成功)insert into news value(11,5);#(执行成功)
next-key 锁【临键锁】
next-key 锁其实包含了记录锁和间隙锁,即锁定一个范围,并且锁定记录本身。InnoDB 默认加锁方式是 next-key 锁。
select * from news where number=4 for update ;
next-key 锁锁定的范围为间隙锁 + 记录锁,即区间(2,4),(4,5)加间隙锁,同时 number= 4 的记录加记录锁,即 next-key 锁的锁定的范围为(2,4],(4,5]。
记录锁、间隙锁、临间锁的区别
update news set number=0 where id 15
sql 默认加的是 next-key 锁。根据上图,next-key 锁的区间为(-∞,1],(1,5],(5,9],(9,11],(11,+∞),上面 id 15,实际上 next-key 锁是加在 [11,+∞)这个范围内,而不是(15,+∞)这个范围内。注意:需要使用锁的字段必须加索引,因为锁是加在索引上的,没有索引则加的表锁。
以上是“MySQL 锁机制的详细分析”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注丸趣 TV 行业资讯频道!
向 AI 问一下细节