1 MySQL 锁简介
1.1 什么是锁
锁是计算机用以协调多个过程间并发拜访同一共享资源的一种机制。MySQL 中为了保证数据拜访的一致性与有效性等性能,实现了锁机制,MySQL 中的锁是在服务器层或者存储引擎层实现的。
1.2 锁用来解决什么问题
锁是用来解决并发事务的拜访问题,咱们曾经晓得事务并发执行时可能带来的各种问题,最大的一个难点是:一方面要最大水平地利用数据库的并发拜访,另外一方面还要确保每个用户能以统一的形式读取和批改数据,尤其是一个事务进行读取操作,另一个同时进行改变操作的状况下。
一个事务进行读取操作,另一个进行改变操作, 咱们前边说过,这种状况下可能产生脏读、不可反复读、幻读的问题。
怎么解决脏读、不可反复读、幻读这些问题呢?其实有两种可选的解决方案:
计划一:读操作 MVCC,写操作进行加锁
该计划性能较好,但可能会读到旧版本记录
计划二:读写操作都加锁
该计划性能个别,然而每次都能够读取到最新的记录,比方在银行场景中,对安全性要求十分高
2 锁的分类
MySQL 中锁有很多,依照模式、粒度等能够分为如下几种类型
3 乐观乐观锁
3.1 乐观锁
1、概念
乐观锁,顾名思义,就是十分乐观,乐观锁认为数据个别状况下不会造成抵触,所以在数据提交更新的时候才会去检测。
2、实现
乐观锁是根本版本号机制实现的,数据表中减少一个 version 字段,读取数据时将 version 一起读出。数据每更新一次,version 字段值 + 1。当批改须要提交时,将读取时的版本号与数据库以后版本号做比拟,如果统一,阐明在此期间无人批改这条记录,不统一则阐明曾经被批改了,提交失败。
3、实用场景
乐观锁实用于读操作多,写操作少的场景
3.2 乐观锁
1、概念
乐观锁是相比拟乐观锁而言的,就是比拟乐观,乐观锁认为数据每次操作都会被批改,所以在每次操作数据时都会加上锁。
2、实现
乐观锁通过共享锁和排他锁实现(上面会讲到这两种锁)
3、实用场景
实用于并发量不大,写操作多,读操作少的场景
4 共享排他锁
4.1 共享锁
1、概念
共享锁,又称读锁,简称 S 锁。当事务对数据加上读锁后,其余事务只能对该数据加读锁,不能加写锁。
2、实现
共享锁加锁办法:select …lock in share mode
4.2 排他锁
1、概念
排他锁,又称为写锁,简称 X 锁,当事务对数据加上排他锁后,其余事务无奈对该数据进行查问或者批改
MySQL InnoDB 引擎默认 update,delete,insert 都会主动给波及到的数据加上排他锁,select 语句默认不会加任何锁类型。
2、实现
排他锁加锁形式:select …for update
5 粒度锁
5.1 全局锁
1、概念
全局锁,从名称上能够了解,全局锁就是对整个 MySQL 数据库实例加锁,加锁期间,对数据库的任何增删改操作都无奈执行。
2、实现
MySQL 提供了一个加全局读锁的办法,命令是 Flush tables with read lock (FTWRL)
3、实用场景
全库数据备份,能够应用全局锁,其余状况不要应用
5.2 表级锁
1、概念
表级锁,给以后操作的这张表加锁,MyISAM 与 InnoDB 引擎都反对表级锁定
MySQL 外面表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)
2、实现
加表锁:lock table read/write
解除表锁:
第一步:找出被锁的表
show processlist
第二步:kill 掉锁表的过程
kill 21;
kill 22;
再次更新 user 表数据
能够失常更新了
5.3 页级锁
页级锁是 MySQL 中锁定粒度介于行级锁和表级锁两头的一种锁。表级锁速度快,但抵触多,行级抵触少,但速度慢。因而,采取了折衷的页级锁,一次锁定相邻的一组记录。BDB 引擎反对页级锁
5.4 行级锁
1、概念
行级锁是 MySQL 粒度最细的锁,产生锁抵触概率最低,然而加锁慢,开销大
MySQL 中只有 InnoDB 引擎反对行锁,其余不反对
2、实现
MySQL 中,行级锁并不是之间锁记录,而是锁的索引。MySQL 在执行 update、delete 语句时会主动加上行锁
6 意向锁
1、概念
意向锁是表锁,为了协调行锁和表锁的关系,反对多粒度(表锁与行锁)的锁并存
2、作用
当有事务 A 有行锁时,MySQL 会主动为该表增加意向锁,事务 B 如果想申请整个表的写锁,那么不须要遍历每一行判断是否存在行锁,而直接判断是否存在意向锁,加强性能。
3、兼容性
动向共享锁 (IS) | 动向排他锁 (IX) | |
---|---|---|
共享锁 | 兼容 | 互斥 |
排他锁 | 互斥 | 互斥 |
7 间隙临键记录锁
1、概念
记录锁、间隙锁、临键锁都是排它锁,而记录锁的应用办法跟排它锁介绍统一。
7.1 记录锁
记录锁是封闭记录,记录锁也叫行锁,例如:
select * from user where id = 1 for update;
它会在 id=1 的记录上加上记录锁,以阻止其余事务插入,更新,删除 id=1 这一行。
7.2 间隙锁
间隙锁基于非惟一索引,它锁定一段范畴内的索引记录。应用间隙锁锁住的是一个区间,而不仅仅是这个区间中的每一条数据
select * from user where id < 10 for update;
即所有在 [1,10)区间内的记录行都会被锁住,所有 id 为 1、2、3、4、5、6、7、8、9 的数据行的插入会被阻塞
7.3 临键锁
临键锁,是记录锁与间隙锁的组合,它的封闭范畴,既蕴含索引记录,又蕴含索引区间,是一个左开右闭区间。临键锁的次要目标,也是为了防止幻读 (Phantom Read)。如果把事务的隔离级别降级为 RC,临键锁则也会生效。
每个数据行上的非惟一索引列上都会存在一把临键锁,当某个事务持有该数据行的临键锁时,会锁住一段左开右闭区间的数据。须要强调的一点是,InnoDB 中行级锁是基于索引实现的,临键锁只与非惟一索引列无关,在惟一索引列(包含主键列)上不存在临键锁。