知识前提复习:
一.概念
锁是计算机协调多个进程或线程并发访问某一资源的机制.
在数据库中,除传统的计算资源(CPU、RAM、I/0)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。
二.分类
这里按照锁的粒度分(也就是锁的作用范围):
- 全局锁
- 表级锁
- 行级锁
1.全局锁
- 全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句,已经更新操作的事务提交语句都将被阻塞。
- 其典型的使用场景是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。
来看不加锁的这个场景:
再看加锁:备份完释放锁!
演示一下: 模拟三个会话
全局锁存在的问题:
数据库中加全局锁,是一个比较重的操作,存在以下问题:
- 如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆。
- 如果在从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志(binlog),会导致主从延迟。
(主从一般用来读写分离、主库是负责增删改、从库负责查询)
在InnoDB引擎中,我们可以在备份时加上参数 --single-transaction 参数来完成不加锁的一致性数据备份。mysqldump --single-transaction kuroot -p123456 itcast>itcast.sql
2.表级锁
表级锁,每次操作锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低。应用在MISAM、InnoDB、BDB等存储引擎中。
对于表级锁又可以分为三种:
- 表锁
- 意向锁
- 元数据锁
2.1-表锁:
读锁不会阻塞其他客户端的读,但是会阻塞写。写锁既会阻塞其他客户端的读,又会阻塞其他客户端的写
语法:
- 1.加锁:locktables 表名.read/write。
- 2.释放锁:unlock tables/客户端断开连接。
- 表共享读锁
注意事项: 对于当前自己的会话来说,命令是串行的,自己加了读锁,执行更新操作就显示报错;而对于其他会话来说,可以等待你释放锁,所以是阻塞而不是报错。
- 表独占写锁
2.2-元数据锁MDL :
简单来说就是读写操作事务未提交时修改表的结构会阻塞
MDL加锁过程是系统自动控制,无需显式使用,在访问一张表的时候会自动加上。MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。为了避免DML与DDL冲突,保证读写的正确性。
在MySQL5.5中引入了MDL,当对一张表进行增删改查的时候,加MDL读锁(共享);当对表结构进行变更操作的时候,加MDL写锁(排他)。
注意:只要不是修改表结构,另外两种又分为查询和增删改,查询是shared_read,增删改是shared_write,修改表结构是exclusive
2.3-意向锁:
简单来说就是为了解决行锁和表锁的冲突问题,不用检查每行的锁情况
只有加的表锁与意向锁兼容才可以添加,不然就会阻塞,一直阻塞到线程A事务提交,释放行锁和意向锁
我是这样理解的:不要被意向锁迷惑了,你就当做意向锁不存在,我就加了行锁,
写数据。别人想怎么加表锁就怎么加。我不乐意别人加表锁,我就拿意向锁拿捏别人
- 要么你只能上共享锁
- 要么你啥锁也别上,等我操作完了事务提交了,释放锁了
3.行级锁(Innodb引擎支持)
行级锁,每次操作锁住对应的行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高。应用在InnoDB存储引擎中。
3.1 行锁
InnoDB实现了以下两种类型的行锁:
- 共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排它锁。
- 排他锁(X):允许获取排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁。
举例:当一个事务执行了下面的语句:
就是对 t_test 表中主键 id 为 1 的这条记录加上 X 型的行锁,这样其他事务就无法对这条记录进行修改了。
当事务执行 commit 后,事务过程中生成的锁都会自动被释放。
3.2 间隙锁:Gap Lock 称为间隙锁,只存在于可重复读隔离级别,目的是为了解决可重复读隔离级别下幻读的现象。
假设,表中有一个范围 id 为(3,5)间隙锁,那么其他事务就无法插入 id = 4 这条记录了,这样就有效的防止幻读现象的发生。
3.3 临键锁
Next-Key Lock 称为临键锁,是 Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。既然是组合,那我们可以理解为只有Gap Lock存在的情况下才会有Next-Key Lock
假设,表中有一个范围 id 为(3,5] 的 next-key lock,那么其他事务即不能插入 id = 4 记录,也不能修改 id = 5 这条记录。
所以,next-key lock 即能保护该记录,又能阻止其他事务将新纪录插入到被保护记录前面的间隙中。