MySQL 各种锁


MySQL 各种锁


正文

一、对MySQL的锁的了解

当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制。

就像酒店的房间,如果大家随意进出,就会出现多人抢夺同一个房间的情况,而在房间上装上锁, 申请到钥匙的人才可以入住并且将房间锁起来,其他人只有等他使用完毕才可以再次使用。

二、隔离级别与锁的关系

隔离级别

  • 读未提交 read uncommitted :当前事务可以读取其他事务未提交的数据,容易导致脏读;
  • 读已提交 read committed :当前事务可以读取其他事务已提交的数据,导致不可重复读现象;
  • 可重复读(默认) repeaableread :同一事务内的select语句,多次读取的结果是一致的,容易导致幻读;
  • 串行化读 serializable :多个事务操作同一个表时,各事务按顺序执行,其他事务堵塞,会锁表,消耗资源,影响效率。

问题解析

脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。

不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交, 导致事务A多次读取同一数据时,结果不一致。

解决办法:MVVC(多版本并发控制),每一行数据都有多个版本,每个版本的记录除了有数据本身外, 还有一个表示版本的事务ID,根据时间先后顺序递增。

幻读:同时开启两个事务,事务A和事务B,当事务A修改了数据,并且提交了, 事务B此时查看不到事务A已经提交了的数据,这样保持事务B先后两次查询结果的一致性, 当事务B执行update操作的时候,是可以更改事务A提交了的update、insert数据, 执行过update操作之后再次select发现数据前后查询不一致!

解决办法:间隙锁,MySQL 把行锁和间隙锁合并在一起,解决了并发写和幻读的问题,这个锁叫做 Next-Key锁。 有索引的情况,如果不是索引列,那么数据库会为整个表加上间隙锁。

与锁的关系

在Read Uncommitted级别下,读取数据不需要加共享锁,这样就不会跟被修改的数据上的排他锁冲突

在Read Committed级别下,读操作需要加共享锁,但是在语句执行完以后释放共享锁。

在Repeatable Read级别下,读操作需要加共享锁,但是在事务提交之前并不释放共享锁,也就是必须等待事务执行完毕以后才释放共享锁。

SERIALIZABLE 是限制性最强的隔离级别,因为该级别锁定整个范围的键,并一直持有锁,直到事务完成。

补充

1、事务隔离级别为读提交时,写数据只会锁住相应的行

2、事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key 锁; 如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。

3、事务隔离级别为串行化时,读写数据都会锁住整张表

4、隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。

5、MYSQL MVCC实现机制参考链接:https://blog.csdn.net/whoamiyang/article/details/51901888

6、关于next-key 锁可以参考链接:https://blog.csdn.net/bigtree_3721/article/details/73731377

三、按照锁的粒度分数据库锁有哪些?

在关系型数据库中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引擎)、表级锁(MYISAM引擎)和页级锁(BDB引擎 )。

MyISAM和InnoDB存储引擎使用的锁

MyISAM采用表级锁(table-level locking)。

InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁。

行级锁,表级锁和页级锁对比

行级锁:MySQL中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小, 但加锁的开销也最大。行级锁分为共享锁和排他锁。

特点:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

表级锁:MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。 最常使用的MyISAM与InnoDB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。

特点:开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。

页级锁:是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。 所以取了折衷的页级,一次锁定相邻的一组记录。

特点:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般

四、从锁的类别上分MySQL都有哪些锁呢?

从锁的类别上分MySQL都有哪些锁呢?像上面那样子进行锁定岂不是有点阻碍并发效率了。

从锁的类别上来讲,有共享锁和排他锁。

共享锁: 又叫做读锁。当用户要进行数据的读取时,对数据加上共享锁。共享锁可以同时加上多个。

排他锁: 又叫做写锁,当用户要进行数据的写入时,对数据加上排他锁。排他锁只可以加一个,他和其他的排他锁、共享锁都相斥。

用上面的例子来说就是用户的行为有两种,一种是来看房,多个用户一起看房是可以接受的。一种是真正的入住一晚, 在这期间,无论是想入住的还是想看房的都不可以。

锁的粒度取决于具体的存储引擎,InnoDB实现了行级锁,页级锁,表级锁。

他们的加锁开销从大到小,并发能力也是从大到小。

五、MySQL中InnoDB引擎的行锁是怎么实现的?

InnoDB是基于索引来完成行锁

例: select * from tab_with_index where id = 1 for update;

for update 可以根据条件来完成行锁锁定,并且 ID 是有索引键的列,如果 ID不是索引键那么InnoDB将完成表锁,并发将无从谈起

六、InnoDB存储引擎的锁的算法有三种

1.Record lock:单个行记录上的锁

2.Gap lock:间隙锁,锁定一个范围,不包括记录本身

3.Next-key lock:record+gap 锁定一个范围,包含记录本身

七、相关知识点:

Innodb对于行的查询使用next-key lock

next-key lock为了解决Phantom Problem幻读问题

当查询的索引含有唯一属性时,将next-key lock降级为record key

Gap锁设计的目的是为了阻止多个事务将记录插入到同一范围内,而这会导致幻读问题的产生

有两种方式显式关闭gap锁:(除了外键约束和唯一性检查外,其余情况仅使用record lock)

A. 将事务隔离级别设置为RC

B. 将参数innodb_locks_unsafe_for_binlog设置为1

八、什么是死锁?怎么解决?

死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。

常见的解决死锁的方法

1、如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。

2、在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率。

3、对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率。

如果业务处理不好可以用分布式事务锁或者使用乐观锁

九、数据库的乐观锁和悲观锁是什么?怎么实现的?

数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。 乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。

实现方式:使用数据库中的锁机制。

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来,通过Version的方式来进行锁定。

实现方式:一般会使用版本号机制或CAS算法实现。

两种锁的使用场景

从上面对两种锁的介绍,我们知道两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下(多读场景), 即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。

但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行Retry,这样反倒是降低了性能, 所以一般多写的场景下用悲观锁就比较合适。

什么是MySQL锁?有哪些锁类型?

参阅 https://mp.weixin.qq.com/s/JchVvLMz2a0eQnzJs1oK-g

待补充。。。






参考资料

视频

阿里P7要求这么低吗?老哥给你讲清楚什么是MySQL的MVCC https://www.bilibili.com/video/BV1t5411u7Fg?p=6

文字

一文搞懂 MySQL 中各种锁,写的太好了 https://mp.weixin.qq.com/s?__biz=MzUyNDc0NjM0Nw==&mid=2247492495&idx=1&sn=5c0b507379c54d45f1aea5bc95df7b89&chksm=fa2a088bcd5d819d0ab3e80cfebb86fc9f586ffdfe7d6c7278b69fcf51de7a326f39e15a2c39&scene=132#wechat_redirect

天呐,怎么这么多锁,行锁、表锁、间隙锁,崩溃了 https://www.bilibili.com/video/BV1LC4y1h7VV

阿里面试官,确实强悍,还好我会MySQL事务ACID的底层实现原理 https://www.bilibili.com/video/BV1ui4y1w7C6

我来告诉你,MySQL是如何通过【索引】找到一条【真实的数据】https://www.bilibili.com/video/BV1wV411h7Fb

【吊打面试官】MySQL索引失效的底层原理,终于有人讲清楚了 https://www.bilibili.com/video/BV1Sp4y1e7W6

MySQL百万数据优化实战 https://www.bilibili.com/video/BV1xV411z7VH

mysql-repeatable read 可重复读隔离级别-幻读实例场景 https://www.cnblogs.com/dreamofprovence/articles/11668080.html


返回