从0开始回顾MySQL---系列七

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 锁1、为什么要加锁?1. 当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况,若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。2. 因此加锁是为了在多用户环境下保证数据库完整性和一致性。2、MySQL都有哪些锁呢?锁的分类:● 按操作分类: ○ 共享锁:也叫读锁。对同一份数据,多个事务读操作可以同时加锁而不互相影响 ,但不能修改数据 ○ 排他锁:也叫写锁。当前的操作没有完成前,会阻断其他操作的读取和写入● 按粒度分类: ○ 表级锁:会锁定整个表,开销小,加锁快;不会出现死锁;锁定力度大,发生锁冲突概率高,并


1、为什么要加锁?


  1. 当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况,若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。
  2. 因此加锁是为了在多用户环境下保证数据库完整性和一致性


2、MySQL都有哪些锁呢?


锁的分类

  • 按操作分类
  • 共享锁:也叫读锁。对同一份数据,多个事务读操作可以同时加锁而不互相影响 ,但不能修改数据
  • 排他锁:也叫写锁。当前的操作没有完成前,会阻断其他操作的读取和写入
  • 按粒度分类
  • 表级锁:会锁定整个表,开销小,加锁快;不会出现死锁;锁定力度大,发生锁冲突概率高,并发度最低,偏向 MyISAM
  • 行级锁:会锁定当前操作行,开销大,加锁慢;会出现死锁;锁定力度小,发生锁冲突概率低,并发度高,偏向 InnoDB
  • 页级锁:锁的力度、发生冲突的概率和加锁开销介于表锁和行锁之间,会出现死锁,并发性能一般
  • 按使用方式分类
  • 悲观锁:每次查询数据时都认为别人会修改,很悲观,所以查询时加锁
  • 乐观锁:每次查询数据时都认为别人不会修改,很乐观,但是更新时会判断一下在此期间别人有没有去更新这个数据

MyISAM和InnoDB存储引擎使用的锁

  • MyISAM采用表级锁(table-level locking)。
  • InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁
LOCK TABLE product_comment READ;
SELECT * FROM product_comment WHERE user_id = 912178 LOCK IN SHARE MODE
UNLOCK TABLE;
LOCK TABLE product_comment WRITE;
SELECT * FROM product_comment WHERE user_id = 912178 FOR UPDATE;
UNLOCK TABLE;

3、什么是乐观锁和悲观锁?如何实现 ?使用场景?


悲观锁

  • 概念:每次查询数据时都认为别人会修改,很悲观,所以一个事务拿到悲观锁后,其他任何事务都不能对该数据进行修改,只能等待锁被释放才可以执行。
  • 数据库中的行锁,表锁,读锁,写锁均为悲观锁。
  • 实现方式:使用数据库中的锁机制。

乐观锁

  • 概念:每次查询数据时都认为别人不会修改,很乐观,但是更新时会判断一下在此期间别人有没有去更新个数据;
  • 实现方式一般会使用版本号机制或 CAS 算法实现。具体来讲,在更新数据时,MySQL 会先检查当前数据的版本号,如果当前版本号与数据库中的版本号相同,则说明该数据没有被其他事务修改,可以更新该数据,并将版本号加 1,以此来表明数据已被变动;否则,说明该数据已被其他事务修改,不能更新该数据,此时 MySQL 会抛出异常。

悲观锁和乐观锁使用前提

  • 对于读的操作远多于写的操作的时候,一个更新操作加锁会阻塞所有的读取操作,降低了吞吐量,最后需要释放锁,锁是需要一些开销的,这时候可以选择乐观锁;
  • 如果是读写比例差距不是非常大或者系统没有响应不及时,吞吐量瓶颈的问题,那就不要去使用乐观锁,它增加了复杂度,也带来了业务额外的风险,这时候可以选择悲观锁。

4、什么是死锁?如何解决死锁?


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

常见的解决死锁的方法

  • 1、如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。
  • 2、在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;
  • 3、对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;

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

排查死锁的一般步骤:

  1. 查看死锁日志 show engine innodb status;
  2. 找出死锁 sql;
  3. 分析 sql 加锁情况;
  4. 模拟死锁案发 ;
  5. 分析死锁日志;
  6. 分析死锁结果。


5、InnoDB引擎的行锁是怎么实现的?

行锁 ,也称为记录锁 ,顾名思义就是在记录上加的锁对于 InnoDB 存储引擎来说,行级锁又分三种,或者说有三种行级锁算法。因此,即使对同一条记录加行锁 ,如果类型不同,起到的功效也是不同的。

InnoDB的行锁的主要实现如下:

  • Record Lock 记录锁

记录锁就是直接锁定某行记录。当我们使用唯一性的索引(包括唯一索引和聚簇索引)进行等值查询且精准匹配到一条记录时,此时就会直接将这条记录锁定。例如 select * from t where id =6 for update; 就会将 id=6 的记录锁定。


  • Gap Lock 间隙锁

间隙锁(Gap Locks) 的间隙指的是两个记录之间逻辑上尚未填入数据的部分,是一个左开右开空间。

间隙锁就是锁定某些间隙区间的。当我们使用等值查询或者范围查询,并且没有命中任何一个 record ,此时就会将对应的间隙区间锁定。例如 select * from t where id =3 for update; 或者 select * from t where id > 1 and id < 6 for update; 就会将(1,6)区间锁定。

  • Next-key Lock 临键锁

临键指的是间隙加上它右边的记录组成的左开右闭区间。⽐如上述的(1,6]、(6,8]等。

临键锁就是记录锁(Record Locks)和间隙锁(Gap Locks)的结合,即除了锁住记录本⾝,还要再锁住索引之间的间隙。当我们使用范围查询,并且命中了部分 record 记录,此时锁住的就是临键区间。注意,临键锁锁住的区间会包含最后一个record的右边的临键区间。例如 select * from t where id > 5 and id <= 7 for update; 会锁住(4,7]、(7,+∞)。

MySQL默认行锁类型就是 临键锁(Next-Key Locks) 。当使用唯一性索引,等值查询匹配到一条记录的时候,临键锁(Next-Key Locks)会退化成记录锁;没有匹配到任何记录的时候,退化成间隙锁。


6、隔离级别与锁的关系?


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

读已提交级别下,读操作需要加共享锁,但是在语句执行完以后释放共享锁;

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

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


7、有哪些优化锁方面的意见?


优化建议

  • 对于特定的事务,可以使用表锁来提高处理速度或者减少死锁的可能;
  • 尽可能让所有数据检索都能通过索引来完成,避免无索引行锁升级为表锁;
  • 合理设计索引,尽量缩小锁的范围;
  • 尽可能减少索引条件及索引范围,避免间隙锁;
  • 尽量控制事务大小,减少锁定资源量和时间长度;
  • 尽可能使用低级别事务隔离(需要业务层面满足需求)。

8、锁机制与 InnoDB 锁算法


MyISAM 和 InnoDB 存储引擎使用的锁

  • MyISAM 采用表级锁(table-level locking)。
  • InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁。

表级锁和行级锁对比

  • 表级锁 MySQL 中锁定 粒度最大 的一种锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM 和 InnoDB 引擎都支持表级锁。
  • 行级锁 MySQL 中锁定 粒度最小 的一种锁,只针对当前操作的行进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。

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

  • Record lock:记录锁,单个行记录上的锁;
  • Gap lock:间隙锁,锁定一个范围,不包括记录本身;
  • Next-key lock:record+gap 临键锁,锁定一个范围,包含记录本身。

9、什么是意向锁?


意向锁是表级锁的一种,它是由数据库引擎自行维护的,用户自己无需也无法操作意向锁。如果用户想要在表上面添加一个共享锁或者排他锁的时候,需要做如下两个检查:

  • 检查这张表的排他锁有没有被其他事务占用,如果有,那么加锁失败;
  • 检查这张表中的行锁有没有被其他事务占用,如果有,那么加锁失败。

如果一张表的数据量特别大,然后我们又想在这张表上添加一个表锁,如果一行一行地去遍历这张表的数据有没有被锁住,效率比较低下。意向锁的存在正是为了解决这个问题。

  • 意向锁能够将检查行锁的时间复杂度由 O(n) 变成 O(1),其加锁的具体做法就是,当一个事务想要获取表中某一行的(共享/排他)锁的时候,它会自动尝试给当前表的加上意向(共享/排他)锁。然后,表锁和行锁之间的兼容互斥性就变成了表锁和意向锁之间的竞争关系
  • 有了意向锁这个表级锁之后,则我们直接判断一次就知道表中是否有数据行被锁定了。

意向锁的兼容性和互斥性

  • 意向锁之间互相兼容,因此针对表中的记录加锁不会因为意向锁而产生互斥,行锁之间的竞争关系是行锁与行锁的竞争,意向锁并不会参与其中;
  • 意向锁只会与表级的共享 / 互斥锁具有互斥性,这里互斥的作用就是用于检查这张表中的行锁有没有被其他事务占用;
  • 意向锁不会与行级的共享 / 排他锁互斥,如记录锁,间隙锁,临键锁。
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6月前
|
存储 SQL 关系型数据库
从0开始回顾MySQL---系列八
分库分表 1、为什么要分库分表? 1. 数据库中的数据量不一定是可控的,随着时间和业务的发展,库中的表会越来越多,表中的数据量也会越来越大,相应地数据操作,例如 增删改查的开销 也会越来越大;另外,若不进行分布式部署,而一台服务器的 资源 (CPU、磁盘、内存、IO 等)是有限的,最终数据库所能承载的数据量、数据处理能力都将遭遇瓶颈。 2. 所以,从 性能 和 可用性 角度考虑,会进行数据库拆分处理,具体地说,把原本存储于一个库的数据分块存储到多个库上,把原本存储于一个表的数据分块存储到多个表上,即 分库分表。 2、分库分表的具体实施策略 分库分表有 垂直切分 和 水平切分 两种方式,在
|
6月前
|
存储 关系型数据库 MySQL
从0开始回顾MySQL---系列三
索引 1、没有索引如何查找数据? 在一个页中的查找,分为两种情况: 以主键为搜索条件 可以在 页目录 中使用二分法快速定位到对应的槽,然后再遍历该槽对应 分组中的记录即可快速找到指定的记录。 以其他列作为搜索条件 对非主键列的查找的过程可就不这么幸运了,因为在数据页中并没有对非主键列建立所谓的 页目录 ,所以 我们无法通过二分法快速定位相应的 槽 。这种情况下只能从 最小记录 开始依次遍历单链表中的每条记录, 然后对比每条记录是不是符合搜索条件。很显然,这种查找的效率是非常低的。 在很多页中的查找,可以分为两个步骤: 定位到记录所在的页。 从所在的页内中查找相应的记录。 在没有索引的情
|
6月前
|
SQL 存储 关系型数据库
Mysql的NULLIF
Mysql的NULLIF
61 1
|
6月前
|
存储 关系型数据库 MySQL
从0开始回顾MySQL---系列一
基础 1、数据库的三范式是什么? 数据库范式是设计数据库时,需要遵循的一些规范。各种范式是条件递增的联系,越高的范式数据库冗余越小。常用的数据库三大范式为: 1. 第一范式(1NF):每个列都不可以再拆分,强调的是列的原子性,即数据库表的每一列都是不可分割的原 子数据项。 2. 第二范式(2NF):在满足第一范式的基础上,非主属性完全依赖于主码(主关键字、主键),消除非主属性对主码的部分函数依赖。 3. 第三范式(3NF):在满足第二范式的基础上,表中的任何属性不依赖于其它非主属性,消除传递依赖。简而言之,非主键都直接依赖于主键,而不是通过其它的键来间接依赖于主键。 2、MySQL 支持哪
|
6月前
|
存储 关系型数据库 MySQL
从0开始回顾MySQL---系列六
11、什么是MVCC? MVCC 全称 Multi-Version Concurrency Control,即多版本并发控制,用来解决读写冲突的无锁并发控制,可以在发生读写请求冲突时不用加锁解决,这个读是指的快照读(也叫一致性读或一致性无锁读),而不是当前读: ● 快照读:实现基于 MVCC,因为是多版本并发,所以快照读读到的数据不一定是当前最新的数据,有可能是历史版本的数据; ● 当前读:读取数据库记录是当前最新的版本(产生幻读、不可重复读),可以对读取的数据进行加锁,防止其他事务修改数据,是悲观锁的一种操作,读写操作加共享锁或者排他锁和串行化事务的隔离级别都是当前读。 -- 简单的sel
|
6月前
|
SQL 关系型数据库 MySQL
从0开始回顾MySQL---系列九
SQL优化 1、一条sql语句执行很慢的原因有哪些? ⚡ 一个SQL执行的很慢,我们要分两种情况讨论: 1. 大多数情况下很正常,偶尔很慢,则有如下原因: ● 数据库在刷新脏页(内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页),例如redo log 写满了需要同步到磁盘。 ● 执行的时候,遇到锁,如表锁、行锁。 ● sql语句写的不好。 2. 这条SQL语句一直执行的很慢,则有如下原因: ● 没有用上索引或者索引失效:比如该字段没有索引,由于对字段进行运算、函数操作导致无法用索引。 ● 有索引可能会走全表扫描: ○ 怎样判断是否走全表扫描? ○ 某
|
6月前
|
存储 缓存 关系型数据库
从0开始回顾MySQL---系列二
InnoDB记录结构 1、InnoDB行格式 ? ● 我们平时是以记录为单位来向表中插入数据的,这些记录在磁盘上的存放方式也被称为 行格式 或者 记录格式 。 ● 设计InnoDB 存储引擎的作者到现在为止设计了4种不同类型的 行格式 ,分别是 Compact 、Redundant 、Dynamic 和 Compressed 行格式。 2、COMPACT行格式 ? 一条完整的记录其实可以被分为 记录的额外信息 和 记录的真实数据 两大部分。 记录的额外信息 这部分信息是服务器为了描述这条记录而不得不额外添加的一些信息,这些额外信息分为3类,分别是 变长字段长度列表 、 NULL值列表 和
|
6月前
|
存储 SQL 关系型数据库
从0开始回顾MySQL---系列五
事务 1、什么是数据库事务? 事务(Transaction)是访问和更新数据库的程序执行单元,是逻辑上的一组操作,要么都执行,要么都不执行。如果任意一个操作失败,那么整组操作即为失败,会回到操作前状态或者是上一个节点。 因此,事务是保持 逻辑数据一致性 和 可恢复性 的重要利器。而锁是实现事务的关键,可以保证事务的完整性和并发性。 事务控制语句: ● BEGIN 或 START TRANSACTION 显式地开启一个事务; ● COMMIT 也可以使用 COMMIT WORK,不过二者是等价的。COMMIT 会提交事务,并使已对数据库进行的所有修改成为永久性的; ● ROLLBAC
|
6月前
|
存储 SQL 关系型数据库
从0开始回顾MySQL---系列四
9、什么是回表(使用索引查询完整数据过程)? 当我们需要查询一条完整的数据的时候: ● 如果是通过聚簇索引来查询数据,例如 select * from user where id=100,那么此时只需要搜索聚簇索引的 B+Tree 就可以找到数据。 ● 如果是通过非聚簇索引来查询数据,例如 select * from user where username=zhangsan',那么此时需要先搜索 username 这一列索引的 B+树,搜索完成后得到主键的值,然后再去搜索聚簇索引的 B+树,就可以获取到一行完整的数据。 对于第二种查询方式而言,一共搜索了两棵 B+树,第一次搜索 B+树 拿到
|
存储 SQL JSON
MySQL学习---17、MySQL8其它新特性
MySQL学习---17、MySQL8其它新特性
下一篇
无影云桌面