Mysql中有哪些锁:
特别说明:Mysql中的锁的目的是锁索引而不是数据本身
锁的力度来说:
库锁:
使用场景:当我们对于一个数据库进行全量的数据备份的时候这个时候我们就会对数据库加一个库锁使得整个数据库处于只读的状态
表锁:
使用场景:当我们对整张表的字段进行修改的时候那么就会将整张表进行一个加锁
意向锁:
这就是当我们对其中的一个数据加锁的时候,这个时候也会有一个意向锁的生成
作用: 就是当我们加表锁的时候不需要对表中的数据进行一一遍历检查是否有行锁,只需要查看是否有意向锁就行了,如果有意向锁的话那么就不会加表锁
行锁(最常见的):
1.记录锁:这个也分为读锁和写锁
这个其实也就是行锁只不过就是换一个名字而已
锁的范围: 只是一条数据而已
读锁(共享锁):这个理解就是当对数据加锁的时候只能够对这个数据进行一个读操作不能进行相关的写操作
加锁方式:
select xx lock in share mode
写锁(排他锁):对数据进行加锁的时候既不能对数据进行读操作也不能进行写操作
加锁方式:
update xx set xx=xx where xx
delete from xx where xx
insert into xx(xx xx xx) values(xx xx xx)
2.间隙锁(只在RR隔离级别下 间隙锁之间是不互斥的):
锁的范围:锁的就是一个区间这个区间是左开右开的
作用:可以从根本上解决幻读的问题
不知道幻读是什么的话可以看我的文章:Mysql的隔离级别以及出现的问题一篇文章即可-CSDN博客
这样的话其他事务就不能在这个区间插入数据了
3.临建锁(Next-key lock):
锁的范围:锁的也是一个区间但是这个是左开右并,这个也是在RR隔离级别下面的默认加锁(在RR隔离级别下)这个的话后面会进行一一介绍, 这个的话其实会出现锁退化的过程后面在加锁的时候细说
拓展的知识:
在RR隔离级别下不仅仅支持行锁而且还支持间隙锁但是在RC隔离级别下是不支持间隙锁的
特别说明:如果一个事务提交的话或者结束的话那么就会释放这个事务持有的锁资源
Mysql是怎么进行加锁的(RR隔离级别下):
这个加锁的话那么是受到两个方面的影响:1.隔离级别 2.是唯一索引还是说非唯一索引
隔离级别的话我已经在上面说明了
1.唯一索引的等值加锁
1.1唯一索引的数据不存在
事务A | 事务B |
begin | |
select * from xx where id=5 for update | begin |
insert into xx(id name age score) values (6,'张三',22,99) | |
conmmit |
这个时候事务B会处于阻塞状态
这个是因为在4-6这个区间的间隙加的是一个间隙锁,这个时候有人心中肯定是用疑惑了:但是刚刚不是说加的是临建锁左开右闭为什么变为左开右开了,这个就是一个退化的过程因为本来是 但是因为id=7的是一个唯一索引索引如果插入肯定是失败的所以就变为
1.2.唯一索引数据存在的话那么肯定是阻塞了这个就不做任何过多的解释了
2.唯一索引的范围加锁:
事务A | 事务B | 事务C |
begin | ||
select * fromxx where id>4 for update | begin | begin |
delete from xx where id=7 | insert into xx(id name age score) values (8,'张三',22,99) | |
commit | commit |
事务B的结果:
事务C的结果:
不难发现这两个的事务的操作都被阻塞了,说明主键ID>4后面的所有的数据都加了锁其中ID>7加的是间隙锁锁的范围为 然后区间加的是临建锁范围为
创建非唯一索引
CREATE INDEX idx_age ON student (age);
3.非唯一索引的等值加锁:这个要考虑到唯一索引和非唯一索引的关系
不清楚地可以看我的文章:索引也不过如此一篇文章带你打破观念-CSDN博客
3.1.非唯一索引的数据存在:
select * from student where age=25 for update
这个就是会在age=25作为右区间,age=24作为左区间加的是临建锁,以及age=25作为左区间,age=27作为右区间加的是间隙锁除以以外对索引 id=1,7加的是记录锁
左区间的间隙锁:
记录锁:
右区间的间隙锁:
3.2非唯一索引的数据不存在:
select * from student where age=26 for update
这个和唯一索引的分析是一样的就是在二级索引中的这个区间加了锁这个也是一样的锁退化的过程,但是这个也有可能会出现插入age=25或者age=27的数据的时候插入失败的情况
我简单列一下排序的数据(数据不完全):
age | 24 | 25 | 25 | 27 |
id | 4 | 1 | 7 | 2 |
插入成功的例子: 就是我插入的数据的age=25但是ID=100,这个时候是阻塞的因为age相同的情况下然后按照ID进行排序那么这个数据应该插在这个区间里面但是这个区间是上锁的所以就会处于阻塞的状态
4.非唯一索引的范围加锁:
select * from student where age>=25 for update
第一个加的肯定是临建锁范围为
,然后将主键ID=1,7加的是记录锁,然后在加临建锁范围为
,最后加的是间隙锁范围为
还是不懂的可以@我
5.没有加索引的加锁:
select * from xx where score=99 for update
因为score不是索引所以在进行加锁的时候会进行全表的扫描,这样就相当于锁住的全表,这时如果其他事务对该表进行增、删、改操作的时候,都会被阻塞。注意:在线上写SQL语句的时候尤其是update delete select xx from xx for update这些加锁语句的时候一定要注意条件有没有走索引,如果没有走索引的话那么就会出现重大的生成问题