【MySQL】锁机制

本文详细介绍了MySQL的锁机制,包括锁的作用、分类、粒度以及InnoDB存储引擎中的锁类型。重点讨论了共享锁、排他锁和意向锁,阐述了它们在并发控制中的应用。此外,还分析了死锁的概念、预防措施,并通过实例展示了读锁和写锁的影响。最后,提供了手动添加锁的操作示例。
摘要由CSDN通过智能技术生成

MySQL设计这个锁是干啥用的

数据库锁设计的初衷是处理并发问题。作为多用户共享的资源,当出现并发访问的时候,为了保证数据的一致性,数据库需要合理地控制资源的访问,制定了一些访问规则。而锁就是用来实现这些访问规则的重要机制。

通过锁实现了在并发情况下数据的一致性


锁的分类

按锁粒度从大到小分类:表锁,页锁和行锁;以及特殊场景下使用的全局锁

如果按锁级别分类则有:共享(读)锁、排他(写)锁、意向共享(读)锁、意向排他(写)锁;

以及Innodb引擎为解决幻读等并发场景下事务存在的数据问题,引入的Record Lock(行记录锁)、Gap Lock(间隙锁)、Next-key Lock(Record Lock + Gap Lock结合)等;

还有就是我们面向编程的两种锁思想:悲观锁、乐观锁


锁粒度

表锁

特点:MySQL各存储引擎中最大颗粒度的锁定机制
优点:

  1. 实现逻辑非常简单,带来的系统负面影响最小
  2. 获取锁和释放锁的速度很快
  3. 有效避免死锁的发生

缺点:出现锁定资源争用的概率也会最高,大大降低并发度

适用场景:表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用

行锁

特点:锁定对象的颗粒度很小
优点:发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力从而提高系统的整体性能
缺点:

  1. 由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大
  2. 行级锁定也最容易发生死锁

使用场景:有大量按索引条件并发更新数据的情况,同时又有并发查询的应用场景。


InnoDB存储引擎中锁的类型

共享锁(S锁)

允许读一行数据

多个事务可以共享一条记录的读锁(锁兼容)
但是如果有别的事务再想要获得该条记录写锁就不行(锁不兼容)

排他锁 (X锁)

允许更新和删除一行数据

与X,S锁不兼容

以上两种锁都是行锁

意向锁

InnoDB存储引擎支持多粒度(granular)锁定,这种锁定允许事务在行级上的
锁和表级上的锁同时存在。为了支持在不同粒度上进行加锁操作,InnoDB存储引擎支持
一种额外的锁方式,称之为意向锁(Intention Lock)。
意向锁意味着事务希望在更细粒度(fine granularity)上进行加锁

意向锁属于表级锁,其设计目的主要是为了在一个事务中揭示下一行将要被请求锁的类型

加意向锁表示,该表中的某一行,要被加上读锁或者写锁

若将上锁的对象看成一棵树,那么对最下层的对象上锁,也就是对最细粒度的对象
进行上锁,那么首先需要对粗粒度的对象上锁

例如,如果需要对页上的记录r进行上X锁,那么分别需要对数据库A、表、页上意向锁X,最后对记录r上X锁。

InnoDB 中的两个表锁:

  • 意向共享锁(IS):表示事务准备给数据行加入共享锁,也就是说一个数据行加共享锁前必须先取得该表的IS锁;

  • 意向排他锁(IX):类似上面,表示事务准备给数据行加入排他锁,说明事务在一个数据行加排他锁前必须先取得该表的IX锁。

意向锁是 InnoDB 自动加的,不需要用户干预。

对于INSERT、UPDATE和DELETE,InnoDB 会自动给涉及的数据加排他锁;对于一般的SELECT语句,InnoDB 不会加任何锁,事务可以通过以下语句显式加共享锁或排他锁。

共享锁:SELECT … LOCK IN SHARE MODE;
排他锁:SELECT … FOR UPDATE;

举例:
看一个例子感受一下意向锁的好处
比如说一个一千条数据的表,事务1和事务2对其操作
事务1读取一行记录
事务2修改整个表
在没有意向锁的情况下:
事务1获取了这个表的一行R的共享锁
事务2想要修改整个表中的所有数据,要求给这表加上写锁
事务2要做的事情是:

  1. 看看表是否被加表锁了
  2. 没有加表锁,还要看看表中的每一行记录是否被上行锁

而再有意向锁的情况下:
3. 事务1在给行加共享锁时,就给表加上了IS锁
4. 事务2再去加排他锁时,首先看看表是否被加表锁了,如果有锁,就会发生阻塞。只有等事务1释放IS锁后才能加X锁,而不用重复那么多一条条去查找是否有行被加锁。

IS锁 不兼容 X锁


死锁

死锁是指两个或两个以上的事务在执行过程中,因争夺资源而造成的一种相互等待的现象。若无外力作用,事务都将无法推进下去。

在并发系统中,不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程进入无限等待的状态,成为死锁。

死锁解决手段:

  1. 超时机制

超时的事务回滚掉,从而释放资源

  1. 等待图机制

采用等待图(wait-for graph)的方式来进行死锁检测
wait-for graph要求数据库保存以下两种信息:
锁的信息链表
事务等待链表

通过上述链表可以构造出一张图,而在这个图中若存在回路,就代表存在死锁,因此资源间相互发生等待。
来看一个例子:
在这里插入图片描述

在 Transaction Wait Lists中可以看到共有4个事务t1、t2、t3、t4,故在wait-for graph中应有4个节点。
在这里插入图片描述
通过上图可以发现存在回路(t1,t2),因此存在死锁。可以发现wait-for graph是一种较为主动的死锁检测机制,在每个事务请求锁并发生等待时都会判断是否存在回路,若存在则有死锁,通常来说InnoDB存储引擎选择回滚undo量最小的事务。

锁操作

手动添加锁

lock table 表名字1 read (write),表名字2 read(write), 其他…
在这里插入图片描述

分析表锁定

show status like ‘table%’;

查看加锁情况

show open tables

手动解锁

unlock tables;

问题:

  1. 什么时候会发生死锁
  2. 为什么表级锁能有效避免死锁的发生
  3. 行级锁定也最容易发生死锁 为什么

测试读锁共享锁
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 ----阻塞

总结:读操作会阻塞写,但不会阻塞读,而写操作会把读和写都阻塞
在这里插入图片描述
在这里插入图片描述
MyISAM偏读
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值