一.锁的介绍
锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,除了传统的计算资源(cpu,ram,i/o)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性,有效性是所有数据库必须解决的一个问题。锁冲突也是影响数据库并发访问性能的一个重要因素。
二.mysql锁的分类
三.mysql中锁的介绍
mysql中的锁,按照锁的粒度分可以分为
全局锁:锁定数据库中的所有表
3.1什么是全局锁
全局锁是针对整个数据库的锁。(我的理解就是一个数据库锁,锁的就是整个数据库)
全局锁里面又分为读锁和写锁。
读锁(共享锁):可以多个线程来读取数据,但是不可写入数据。
写锁(排他锁):不允许其他线程来读取和写入数据。
3.2 应用场景
dump表中所有数据的时候可以加入全局锁,保证数据的一致性。
利用mvcc机制也同样可以实现数据dump,但是不用加锁
3.3 全局锁具体示例
开启读锁:flush tables with read lock;
开启读锁,其他线程不可以 修改操作,阻塞中或报错,查询可以
释放锁后可以修改成功
表级锁: 每次操作锁住整张表。
3.1什么是表级锁
每次操作锁住整张表,开销小,加锁快,不会出现死锁,锁定的粒度大,发生锁冲突的概率最高,并发低。
表级锁里面又分为表共享读锁和表独占写锁。
表共享读锁 :{读锁(共享锁)}:可以多个线程来读取数据,但是不可写入数据。
表独占写锁 : {写锁(排他锁)}:不允许其他线程来读取和写入数据。
3.2 应用场景
1.读密集型的场景
2.写操作不是很密集的场景
3.3 表级锁具体演示
1.执行 alter table;
2.执行drop table 或者 truncate table;
3.lock tables t1 write,t2 read.
以上命令给表1加上写锁,给表2 加上读锁。
开启读锁的效果:
开启写锁
查看 锁的状态:show open tables where in_use > 0;
总结:
在同一个客户端中:
开启表的读锁,不可以进行修改,只可以查询
开启表的写锁,可以修改,可以查询
在不同的客户端中:
开启表的读锁,不可以进行修改,只可以查询
开启表的写锁,不可以修改,不可以查询
开启表的写锁:下面是在不同的客户端中查询阻塞
缺点:并发性能下降。
行级锁:每次操作锁住对应的行数据。
3.1什么是行级锁
锁定的是数据的一行,粒度小,能提供更好的并发性,需要更多的资源。
行级锁里面又分为共享锁和排他锁。
共享锁 :{读锁(共享锁)}:可以多个线程来读取数据,但是不可写入数据。
排他锁 :{写锁(排他锁)}:不允许其他线程来读取和写入数据。
3.2使用场景
1.高并发
2.遇到事物的操作
查看那些是行级锁:select * from performance_schema.data_locks;
行级锁, 如果不在事物中执行,语句执行完毕,锁释放
在事物中执行,在没有commit之前这个排他锁一直存在
案例演示:
执行排他锁(写锁):select ... for update
第一个窗口开始事物,设置排他锁
第二个窗口可以查询,不可以修改
执行共享锁(读锁):select......lock in share mode
第一个窗口开启 事物,开启共享锁
第二个窗口 可以查询,不可以修改
总结: 开启行的共享锁和排他锁不同窗口都可以读,不可以修改。
造成的问题:
1. 在多个事物当中会发生死锁(事物可以理解为多个线程)。
2.锁升级 (锁定多行后,发现还不如锁定整个表)
3.不同的事物隔离级别会影响锁的性能和行为,根据具体的场景来调整事物隔离级别。
按照锁的状态范围分类
共享意向锁
排他意向锁
意向锁个人理解就是一个“信号标记性能锁”,以前要去一行一行遍历表中的数据,判断是否存在行锁,现在去看一下,信号标记就可以。
概念 :意向锁是表锁,为了协调行锁和表锁的关系,支持多粒度(表锁与行锁)的锁并存。
作用:当有事物(线程)A有行锁时,mysql会自动为该表添加意向锁,事物(线程)b如果想申请整个表的写锁,那么不需要遍历每一行判断是否存在行锁,而直接判断是否存在意向锁,增强性能。
查看那些是行级锁:select * from performance_schema.data_locks;
案例演示:
1.第一个窗口开启事物,并开启排他锁
2.查看当前的锁
查看LOCK_TYPE,LOCK_MODE 第一个是表级的意向排他锁 lX显示为排他锁
X是排他锁 LOCK_TYPE显示为 record 行级别。
3.在另一个窗口中添加写锁是阻塞状态:
总结:
间隙锁(范围锁)
和临界锁类似,是一个范围锁。两个值之间的空隙加锁。
演示示例:
1.查看当前的表结构
2.开启事物设置间隙锁(查询的id一定要不存在)
3.开启一个窗口,看到 id < 7的可以正常插入,id > 7 < 10的数据插入失败
临界锁
什么是临界锁 next-key 可以理解为一种特殊的间隙锁,也可以理解为一种特殊的算法。通过临界锁可以解决幻读的问题。每个数据行上的非唯一索引列上都会存在一把临界锁,当某个事物持有该数据的临界锁时,会锁住一段左开右闭区间的数据。innodb中行级锁是基于索引实现的,临界锁只与非唯一索引列有关,在唯一索引列上不存在临界锁。(把下面的演示做一遍才理解的更深刻)
演示案例
第一个窗口开启事物设置,设置临界锁为2000,表里面已经有1000的数据,
所以区间是1000-2000
第二个窗口在插入大于1000 小于 2000范围的数据是阻塞状态,插入不进去
发现插入小于1000也处于阻塞状态,拉拉了。一定要是 (每个数据行上的非唯一索引列上都会存在一把临界锁)才会有临界锁
mysql锁总结:
mysql中锁的分类 | 可以多事物(线程)操作 | 不可以多事物(线程)操作 |
数据库锁(全局锁) | 读锁 | 写锁 |
表级锁 | 共享 lock tables t2 read. | 排他 lock tables t1 write; |
行级锁 | 共享锁 select ..... lock in share mode; | 排他锁 select..... for update; |
共享锁 ,读锁 都可以理解为 共享读锁
排他锁 ,写锁 都可以理解为 排他写锁
间隙锁是innodb引擎为了解决幻读,临界锁也是为了解决幻读。
参考:阿里一面:MySQL锁你了解吗?说一下什么是mysql间隙锁?招架不住啊。。_哔哩哔哩_bilibili