1、为什么要有锁,锁是什么?
数据库是一个多用户使用的共享资源,比如一个用户表 t_user,两个浏览器前面的人登录了同个一个账号,把电话号码改了。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性(脏读,不可重复读,幻读等),可能产生死锁。为了解决这个问题,加锁是一个非常重要的技术,对实现数据库并发控制是一个好的方案。
简单说,当一个执行sql语句的事务想要操作表记录之前,先向数据库发出请求,对你访问的记录集加锁,在这个事务释放这个锁之前,其他事务不能对这些数据进行更新操作。
锁是
事务对某个数据库中的资源(如表和记 录)存取前,先向系统提出请求,封锁该资源,
事务获得锁后,即取得对数据的控制权,在事务释放它的锁之前,其他事务不能更新此数据。
当事务撤消后,释放被 锁定的资源。
2、锁的分类
MySQL 中的锁,按照锁的粒度分,分为以下三类:
- 全局锁:锁定数据库中的所有表。
- 表级锁:每次操作锁住整张表。
- 行级锁:每次操作锁住对应的行数据。
3、全局锁
3.1什么是全局锁,作用是什么?
全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的 DML 的写语句, DDL 语句,已经更新操作的事务提交语句都将被阻塞。
其典型的使用场景是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。
数据库不加锁,进行备份时,如果同时有业务更新操作,将会导致数据不一致
3.2全局锁语法
加全局锁后,到释放锁之前,可以对数据库进行查询操作,但是不能进行更新操作。
3.3全局锁的缺点
4、表级锁
4.1表级锁的概念与分类
表级锁, 每次操作锁住整张表 。锁定粒度大,发生锁冲突的概率最高,并发度最低。应用在 MyISAM 、InnoDB 、 BDB 等存储引擎中。
对于表级锁,主要分为以下三类:
- 表锁
- 元数据锁(meta data lock,MDL)
- 意向锁
4.2表锁
表锁主要用来锁定表对当前用户及其他用户对表的读写权限。
对于表锁,分为两类:
- 表共享读锁(read lock) 简称读锁
- 表独占写锁(write lock) 简称写锁
语法:
- 加锁:lock tables 表名... read/write。
- 释放锁:unlock tables / 客户端断开连接
读锁的特点:
添加读锁后,当前用户和其他用户都只能读,不能写。
写锁的特点:
添加写锁后,当前用户既可以读也可以写,但是其他客户端不能读也不能写。
4.3元数据锁
什么是元数据锁,作用是什么?
meta data lock , 元数据锁,简写 MDL 。
MDL 加锁过程是 系统自动控制 ,无需显式使用, 在访问一张表的时候会自动加上 。 MDL 锁主要作用是 维护表元数据的数据一致性 ,在表上有活动事务的时候,不可以对元数据进行写入操作。 为了避免 DML 与 DDL 冲突,保证读写的正确性。
这里的元数据,大家可以简单理解为就是一张 表的表结构 。 也就是说, 某一张表涉及到未提交的事务时,是不能够修改这张表的表结构的。
在 MySQL5.5 中引入了 MDL ,当对一张表进行增删改查的时候,加 MDL 读锁 ( 共享 ) ;当对表结构进行变更操作的时候,加 MDL 写锁 ( 排他 ) 。
元数据锁类型
下边是常见操作时,数据库自动对表添加的元数据锁
注意:在对表进行操作时,是会自动添加元数据锁,但是当表语句执行结束时,元数据锁会自动释放,所以为了能够查询到确实添加了元数据锁,所以以下操作需要先开启事务。
元数据锁之间的关系
4.4意向锁
什么是意向锁,作用是什么?
前提:在执行DML语句时,会对涉及到的行加行锁
所以意向锁的作用是:为了避免 DML 在执行时,加的行锁与表锁的冲突,在 InnoDB 中引入了意向锁,使得表锁不用检查每行数据是否加锁,使用 意向锁来减少行锁的检查
意向锁分类
5、行级锁
什么是行级锁?原理是什么?
行级锁, 每次操作锁住对应的行数据 。锁定粒度最小,发生锁冲突的概率最低,并发度最高。应用在InnoDB 存储引擎中。
InnoDB 的数据是基于索引组织的,行锁是通过 对索引上的索引项加锁来实现 的,而不是对记录加的锁
行级锁分类
InnoDB行锁是通过给索引上的索引项加锁来实现的, 只有通过索引条件检索数据,InnoDB才使用行级锁或者间隙锁,否则,InnoDB将使用表锁
行锁
常见的sql语句,在执行时,会自动的给行数据加锁。
如insert、update、delete 以及select ... for update语句都会添加排他锁
select ... lock in share mode 会添加共享锁
正常select语句不会添加任何锁。
InnoDB 实现了以下两种类型的行锁:
共享锁( S ):
允许一个事务去读一行,其他事务执行sql时,如果是添加的共享锁,可以执行,如果添加的 是排他锁,不能执行
(也就是如果一个sql语句是查询语句,那么其他的事务可以进行查询操作,不能进行更新)
排他锁( X ):
允许获取排他锁的事务更新数据,其他的事务来进行更新或者是读取数据都不能执行。
(也就是如果一个sql语句是更新(更删改)语句,那么其他的事务既不能进行查询操作,也不能进行更新)
执行sql语句后,data_locks表中未查询到加锁,其他事务可以进行更删改查操作
执行select ... in share mode后,data_locks表中有S锁,此时右边事务进行查询操作可以进行,data_locks表中会有两个s锁,如果进行更新操作失败。
行锁升级为表锁场景
InnoDB 的行锁是针对于 索引 加的锁, 不通过索引条件检索数据 ,那么 InnoDB 将对表中的所有记
录加锁,此时 就会 升级为表锁 。
间隙锁&临键锁
锁定一个范围,但不包含记录本身,即间隙锁为开区间,例如一个表中有id为1,3,8,三条记录,3和8之间还可以进行数据插入,那么3-8之间的数据是否允许操作(插入)呢,就需要一个锁来控制,这个锁就是间隙锁
- 索引上的等值查询(唯一索引),给不存在的记录加锁时, 优化为间隙锁 。
- 索引上的等值查询(非唯一普通索引),向右遍历时最后一个值不满足查询需求时,next-key
lock 退化为间隙锁。
- 索引上的范围查询(唯一索引)--会访问到不满足条件的第一个值为止。
A. 索引上的等值查询 ( 唯一索引 ) ,给不存在的记录加锁时 , 优化为间隙锁 。