Mysql中锁的使用场景是什么

86次阅读
没有评论

共计 3340 个字符,预计需要花费 9 分钟才能阅读完成。

这篇文章主要讲解了“Mysql 中锁的使用场景是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着丸趣 TV 小编的思路慢慢深入,一起来研究和学习“Mysql 中锁的使用场景是什么”吧!

一、常见锁类型

表级锁,锁定整张表

页级锁,锁定一页

行级锁,锁定一行

共享锁,也叫 S 锁,在 MyISAM 中也叫读锁

排他锁,也叫 X 锁,在 MyISAM 中也叫写锁

悲观锁,抽象性质,其实不真实存在

乐观锁,抽象性质,其实不真实存在

常见锁类型二、Mysql 引擎介绍

其实 mysql 中的引擎有很多种类,其中 InnoDB 和 MyISAM 引擎最常用

在 mysql5.5 版本前默认使用 MyISAM 引擎,之后使用 InnoDB 引擎

查看数据库引擎命令如下

show variables like  %storage_engine%

三、常用引擎间的区别

MyISAM 操作数据都是使用的表锁,你更新一条记录就要锁整个表,导致性能较低,并发不高。当然同时它也不会存在死锁问题。

而 InnoDB 与 MyISAM 的最大不同有两点:一是 InnoDB 支持事务;二是 InnoDB 采用了行级锁。

在 Mysql 中,行级锁并不是直接锁记录,而是锁索引。索引分为主键索引和非主键索引两种,如果一条 sql 语句操作了主键索引,Mysql 就会锁定这条主键索引;如果一条语句操作了非主键索引,MySQL 会先锁定该非主键索引,再锁定相关的主键索引。

InnoDB 行锁是通过给索引项加锁实现的,如果没有索引,InnoDB 会通过隐藏的聚簇索引来对记录加锁。也就是说:如果不通过索引条件检索数据,那么 InnoDB 将对表中所有数据加锁,实际效果跟表锁一样。因为没有了索引,找到某一条记录就得扫描全表,要扫描全表,就得锁定表。

四、共享锁与排他锁

数据库的增删改操作默认都会加排他锁,而查询不会加任何锁。

共享锁:对某一资源加共享锁,自身可以读该资源,其他人也可以读该资源(也可以再继续加共享锁,即 共享锁可多个共存),但无法修改。要想修改就必须等所有共享锁都释放完之后。

排他锁:对某一资源加排他锁,自身可以进行增删改查,其他人无法进行任何操作。

// 共享锁
select * from  表名  lock in share mode
// 排他锁
select * from  表名  for update

五、排他锁的实际应用

这里我们以两个操作数据库的请求为例,假设这两个请求分别为 T1 和 T2

假设 T1 为查询请求,而 T2 为更新数据请求,在 T1 查询很长时间的时候,还没有返回结果,但是这时候 T2 过来请求更新了

这个流程应该是: T1 运行加共享锁、T2 运行、发现 T1 未完成等待其完成、T1 完成、T2 开始执行

T2 之所以要等待,是因为 T2 执行更新的时候需要给表加排他锁,但是数据库规定,不能在同一资源上同时共存这两种锁,所以 T2 必须等 T1 执行完,释放锁后,才可以正常操作

T1: select * from  表名  lock in share mode // 假设还未返回结果
T2: update  表名  set name= autofelix

六、共享锁的实际应用

如果 T1 和 T2 都是执行的查询,也就是都加共享锁

这时候就不用等待,可以立马执行

因为同一资源上可以同时存在多个共享锁,也被称为,共享锁与共享锁兼容

意味着共享锁不阻止其他人同时读取资源,但是阻止其他人修改资源

T1: select * from table lock in share mode
T2: select * from table lock in share mode

七、死锁的发生

假设 T1 和 T2 都同时执行 2 个资源操作,分别是查询和更新数据

假设 T1 和 T2 同时达到 select,T1 对表加共享锁,而 T2 也加上了共享锁

当 T1 的 select 执行完毕,准备执行 update 时

根据锁机制,T1 的共享锁必须升级到排他锁才可以执行接下来的 update 操作

在升级排他锁之前,必须等 T2 的共享锁释放,同理,T2 也在等 T1 的共享锁释放

于是都在等待对方的锁释放,导致程序卡死,这种情况就是死锁

T1:  开启事务, 执行查询更新两个操作
 select * from table lock in share mode
 update table set column1= hello 
T2:  开启事务, 执行查询更新两个操作
 select * from table lock in share mode
 update table set column1= world

八、另一种发生死锁的情景

当 T1 和 T2 都是只执行更新语句的时候

如下程序所示,这种语句非常的常见,很多人觉得他会产生死锁,其实要看情况

如果 id 是主键,由于主键机制,并不需要全表扫描,直接可以更新当前数据,所以不会产生死锁

如果 id 是普通字段,那么当 T1 加上排他锁之后,T2 为了找到 id=20 条数据,必须进行全表扫描,当他扫到第 10 条的时候,发现这里有排他锁,导致全表扫描进行不下去,就会导致等待

T1: begin
 update table set content= hello  where id=10
T2: begin
 update table set content= world  where id=20

九、死锁的解决方式

就是让 T1 和 T2 顺序执行,比如 T1 在执行完 select 后,立马给自身加上排他锁,这样 T2 不得不等待 T1 执行完才能继续

但是如果有很多请求过来的话,都必须等待,这对用户特别的不友好

所以,某些数据库引入了另一种方式,叫做更新锁,这里 mysql 除外,不存在更新锁

更新锁其实就是排他锁的另一种实现,只是他允许其他人读的同时加共享锁,但是不允许其他操作,除非释放了更新锁

流程大概如此: T1 执行完 select 加上更新锁,T2 执行查询完,准备加更新锁,发现已经有了,就等待,其他请求过来,如果查询是不受影响的,但是更新才等待

这相比上面的查询也要等待增加了效率

T1: begin
 select * from table for update
 update table set content= hello 
T2: begin
 select * from table for update
 update table set content= world
T1: begin
 select * from table [加更新锁操作]
 update table set content= hello 
T2: begin
 select * from table [加更新锁操作]
 update table set content= world

十、意向锁和计划锁

计划锁与程序猿无关,不需要了解

意向锁,Innodb 特有,分为意向共享锁和意向排他锁

意向共享锁: 表示事务获取共享锁时,必须先得获取该表的意向共享锁

意向排他锁: 表示事务获取排他锁时,必须先得获取该表的意向排他锁

我们知道要对整个表加锁,必须保证表内不存在任何锁

如果一行行的去检查是否加锁,效率必然极低,这时候可以检测意向锁是否被占用即可

十一、乐观锁和悲观锁

乐观锁和悲观锁都是针对 select 而言的

比如在商品抢购中,用户购买后库存需要减 1,而很多用户同时购买时,读出来的库存数量一样,然后多个用户同时用该库存去减 1

这种做法必然会出现很大的漏洞,如果向在淘宝,京东出现这种情况,你就可以打包回家种地了

这种情况如何解决呢,其实可以使用悲观锁进行解决,说白了也就是排他锁

用户进来查库存的时候,就加上排他锁,等他所有操作完成后,再释放排他锁,让其他人进来

不让用户等待,就可以使用乐观锁方式解决,乐观锁一般靠表的设计和时间戳来实现

一般是在表中添加 version 或者 timestamp 时间戳字段

这样就会保证如果更新失败,就表示有其他程序更新了数据库,就可以通过重试解决

update table set num=num-1 where id=10 and version=12

感谢各位的阅读,以上就是“Mysql 中锁的使用场景是什么”的内容了,经过本文的学习后,相信大家对 Mysql 中锁的使用场景是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是丸趣 TV,丸趣 TV 小编将为大家推送更多相关知识点的文章,欢迎关注!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-13发表,共计3340字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)