MySQL锁机制6
MySQL设计这个锁是干啥用的
数据库锁设计的初衷是处理并发问题。作为多用户共享的资源,当出现并发访问的时候,为了保证数据的一致性,数据库需要合理地控制资源的访问,制定了一些访问规则。而锁就是用来实现这些访问规则的重要机制。
锁的分类
按锁粒度从大到小分类:表锁,页锁和行锁;以及特殊场景下使用的全局锁
如果按锁级别分类则有:共享(读)锁、排他(写)锁、意向共享(读)锁、意向排他(写)锁;
以及Innodb引擎为解决幻读等并发场景下事务存在的数据问题,引入的Record Lock(行记录锁)、Gap Lock(间隙锁)、Next-key Lock(Record Lock + Gap Lock结合)等;
还有就是我们面向编程的两种锁思想:悲观锁、乐观锁
锁粒度
表锁
特点:MySQL各存储引擎中最大颗粒度的锁定机制
优点:
- 实现逻辑非常简单,带来的系统负面影响最小
- 获取锁和释放锁的速度很快
- 有效避免死锁的发生
缺点:出现锁定资源争用的概率也会最高,大大降低并发度
适用场景:表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用
行锁
特点:锁定对象的颗粒度很小
优点:发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力从而提高系统的整体性能
缺点:
- 由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大
- 行级锁定也最容易发生死锁
使用场景:有大量按索引条件并发更新数据的情况,同时又有并发查询的应用场景。
InnoDB存储引擎中锁的类型
共享锁(S锁)
允许读一行数据
排他锁 (X锁)
允许更新和删除一行数据
以上两种锁都是行锁
意向锁
意向锁属于表级锁,其设计目的主要是为了在一个事务中揭示下一行将要被请求锁的类型
InnoDB 中的两个表锁:
-
意向共享锁(IS):表示事务准备给数据行加入共享锁,也就是说一个数据行加共享锁前必须先取得该表的IS锁;
-
意向排他锁(IX):类似上面,表示事务准备给数据行加入排他锁,说明事务在一个数据行加排他锁前必须先取得该表的IX锁。
意向锁是 InnoDB 自动加的,不需要用户干预。
对于INSERT、UPDATE和DELETE,InnoDB 会自动给涉及的数据加排他锁;对于一般的SELECT语句,InnoDB 不会加任何锁,事务可以通过以下语句显式加共享锁或排他锁。
举例:
看一个例子感受一下意向锁的好处
比如说一个一千条数据的表,事务1和事务2对其操作
事务1读取一行记录
事务2修改整个表
在没有意向锁的情况下:
事务1获取了这个表的一行R的共享锁
事务2想要修改整个表中的所有数据,要求给这表加上写锁
事务2要做的事情是:
- 看看表是否被加表锁了
- 没有加表锁,还要看看表中的每一行记录是否被上行锁
而再有意向锁的情况下:
3. 事务1在给行加共享锁时,就给表加上了IS锁
4. 事务2再去加排他锁时,首先看看表是否被加表锁了,如果有锁,就会发生阻塞。只有等事务1释放IS锁后才能加X锁,而不用重复那么多一条条去查找是否有行被加锁。
死锁
死锁解决手段:
- 超时机制
- 等待图机制
在 Transaction Wait Lists中可以看到共有4个事务t1、t2、t3、t4,故在wait-for graph中应有4个节点。
通过上图可以发现存在回路(t1,t2),因此存在死锁。可以发现wait-for graph是一种较为主动的死锁检测机制,在每个事务请求锁并发生等待时都会判断是否存在回路,若存在则有死锁,通常来说InnoDB存储引擎选择回滚undo量最小的事务。
锁操作
手动添加锁
分析表锁定
查看加锁情况
手动解锁
问题:
- 什么时候会发生死锁
- 为什么表级锁能有效避免死锁的发生
- 行级锁定也最容易发生死锁 为什么
测试读锁共享锁
1.建表 (MyISAM)
2.锁表read
3.session1访问
4.session2访问
5.加了读锁是否可以修改?session1 cannot write
6.session1是否可读别的表 cannot
7、session2 write 对于session1加了读锁的表会发生阻塞、知道session1释放锁,session2操作完成
session1 对表A加写锁
1.session1是否可读 yes
2.session1是否可写 yes
3.session1是否可以查看其它表 no
4.session2是否可以读表A ----阻塞
5.session2是否可以写表A ----阻塞