MySQL----锁
一、概述
首先为什么需要锁,这是因为在高并发的情况下,如果没有锁,很容易出现脏读,不可重复读,幻读的问题,而锁的合理使用就可以很大程度上避免这些情况,MySQL的锁,在主流的Innodb引擎下,按照锁的粒度分为 全局锁,表级锁,行级锁。全局锁:锁住整个数据库;表级锁:锁住整个表;行级锁:锁住对应的行数据。这些锁,就是MySQL实现不同事务隔离级别的基础。
二、介绍锁
1.全局锁
锁的粒度很大,主要应用场景就是数据库的全局备份,加上全局锁可以保证数据的一致性,保证数据的完整性。加上全局锁后,数据库中还是可以进行select查询的。
语法
加锁:flush tables with read lock;
解锁:Unlock tables;
可以通过使用:
mysqldump --single-transation -u+用户名 -p+数据库密码 数据库名 > 文件名.sql;
来实现在不加全局锁的情况下也能完成全局备份。
2.表级锁
表级锁分为3类:
1.表锁
表锁又分为表共享读锁/读锁,表独占写锁/写锁/排他锁,其中加读锁的情况下是所有客户端都只能读不能写,而加写锁的情况下是只有加了写锁的客户端可以读和写,其他客户端都不能进行读写。
语法:
加锁:lock tables 表名 read/write;
解锁:Unlock tables/客户端断开连接。
2.元数据锁
元数据其实就是指数据库中的表结构,当表中有活跃事务时,如果此时进行表结构修改,此时就会因为有元数据锁的存在而失败,元数据锁的存在,就是为了避免DML和DDL语句的冲突。
元数据锁简称MDL,也分为读锁和写锁/排他锁。
在MySQL5.5版本后,当执行DDL语句时,会自动加上MDL读锁,此时不能进行表结构的修改,当执行DML语句时,会自动加上MDL写锁。
3.意向锁
意向锁是用于解决在添加表锁时,需要一行一行的查找是否有活跃事务,从而导致效率过低的情况。意向锁也分为两类:意向共享锁IS,意向排它锁IX。和DML一样,也是自动加锁。
IS:与表锁中的读锁兼容,与表锁中的写锁互斥。由 select ..... lock in share mode;语句触发。
IX:与表锁的读锁和写锁冲突,但是意向锁之间是不互斥的。由 insert,update,delete以及 select....
for update来触发。
我们可以通过以下语句来查看当前数据库中锁的情况:
select object_schema,object_name,index_name,
lock_type,lock_mode,lock_data from performance_schema.data_locks;
但是注意一下,在MySQL中,存在隐式提交事务的情况,就是在一个还未提交的事务中进行添加表锁/全局锁时,即使此时存在冲突的意向锁,但是添加表锁或全局锁时会自动提交事务,从而使得意向锁失效,此时仍可以加上表锁。
3.行级锁
行锁在Innodb中是通过对索引上的索引项加锁来实现的,并非是对数据行进行加锁。行级锁是最小粒度的锁,也是并发性能最高的。
分为 行锁,间隙锁,临建锁。
1.行锁
锁定单个行记录的锁,防止其他事务进行update/delete,很显然,它不能解决幻读问题,所以在RR和RC隔离级别中都有。
行锁又分为读锁/共享锁S和写锁/排他锁X,S:允许一个事务去读这一行,但是阻止其他事务来获得X。
X:允许获得锁的事务来更新和查询这一行数据,但是不允许其他事务获得S和X。
不同SQL语句触发的锁
SQL语句类型 | 行锁类型 | 获得锁的方式 |
insert | X | 自动 |
update | X | 自动 |
delete | X | 自动 |
select(普通类型) | 不加锁 | |
select....lock in share mode | S | 自动 |
select....for update | X | 自动 |
还有下面两种情况:
1.当针对唯一索引进行检索时,对已经存在的记录进行等值匹配时,会自动优化为行锁。这是因为行锁是和索引息息相关的,如果索引查询出的值唯一且存在,当然会成为行锁。
2.当不通过索引来查询数据时,将会上升为表锁。
2.间隙锁/临建锁
这俩哥们放一块,是因为它们经常相互转换。它们主要是解决幻读问题的,将间隙加上锁,就是让这个区域不能进行insert,在普通索引的情况下,这样有效避免了多次查询结果不一样的情况。间隙锁也是可以共存的。
在RR隔离级别下,Innodb默认使用临建锁。当发生一下情况下时:
1.进行唯一索引的等值查询时,如果给不存在的记录进行加锁时,或优化为间隙锁。将目标索引(如Id)的相邻的两个值之间进行加锁。
2.进行普通索引的等值查询时,因为普通索引可能会重复,所以当向右遍历到最后一个值不满足查询条件时,临建锁会退化为间隙锁。此时就是将目标值到前一个索引和到后一个索引的间隙都加上锁。
3.索引上的范围查询,而且是唯一索引时,会访问到不满足条件的第一个值为止,如果是>的情况,就会将正无穷到条件值都加上间隙锁。