MySQL~锁的大集合(S锁、X锁、意向锁、自增锁、元数据锁、记录锁、间隙锁、临键锁、全局锁、死锁)
文章目录
- 什么是锁机制
- 并发的访问相同数据的情况
- 读读
- 写写
- 读写/写读
- 锁的分类
- 共享锁(S锁)
- 排他锁( X锁)
- 表锁
- 表级别的S、X锁.
- 意向锁.
- 自增锁
- 元数据锁
- 行锁
- 记录锁
- 间隙锁
- 临键锁
- 插入意向锁
- 页锁
- 其他锁
- 全局锁
- 死锁
什么是锁机制
锁是计算机协调多个进程或线程并发访问某一资源的控制.
- 锁不仅仅限于数据库领域,在计算机中,当多个进程或线程并发的访问某个数据的时候,对于一些重要敏感的数据,为了保证数据的
完整性
和一致性
,我们需要保证最多只有一个线程在访问,所以诞生了锁机制。 - 锁机制的作用是对并发操作进行控制
- 在MySQL中,锁保证了事务的隔离性
并发的访问相同数据的情况
读是查询操作,写是增删改操作.
读读
两个事务并发读取相同数据的情况.
- 读读操作都是查询操作,本身对数据没有什么影响,所以没有什么问题.
写写
两个并发事务相继对同一个数据进行修改的情况.
- 写写情况下,会发生数据脏写问题,脏写问题非常严重,任何的事物隔离级别都不允许发生这个问题
- 为了避免脏写,数据库强制未提交事务必须排队执行,通过锁实现强制.
- 假设事务T1想要修改一条记录,如果内存中没有与之相关的锁结构,会生成一个锁结构与它进行关联。简化图:.
锁结构中,trx标识该锁结构属于哪个事务,is_waiting标识该事务是否在等待
- T1之前没有任何事务对该记录进行修改,所以is_waiting是false,表示无须等待,可以直接修改,即加锁成功.在事务T1未提交之前,如果事务T2也想对该记录修改,就需要等待,is_waiting是true,需要等待,即加锁失败.
- 在事务T1提交后,锁会释放,交给T2,T2的is_waiting变为false,然后T2就会开始执行.
读写/写读
两个并发事务,对于同一条数据,一个读取,一个修改。
- 读写/写读情况下会发生脏读、不可重复读、幻读问题
- 解决这些问题有两个办法:一是对读操作使用MVCC,写操作进行加锁.方法二是读写操作都进行加锁.
锁的分类
- 对数据的操作类型划分:共享锁(读锁)、排他锁(写锁)
- 从锁粒角度划分:表锁、行锁、页锁
- 从锁的态度进行划分:悲观锁、乐观锁
- 从加锁方式划分:隐式锁、显式锁
- 从其他角度划分:全局锁、死锁
共享锁(S锁)
- 共享锁(
Shared Lock
) 也叫读锁,对于同一份数据,多个事务进行读取时可以同时进行互不影响
排他锁( X锁)
- 排他锁(
Exclusive Lock
)也叫写锁、X锁,对于同一份数据,当一个数据进行写操作时,禁止其他事务的读、写操作.
对于Innodb引擎,读锁和写锁可以加在表上,也可以加在行上.
两个锁之间的兼容性
锁定读操作
读取时加S锁:
SELECT ... Lock in share mode;
或者
select....for share;
为这条记录添加了S锁后,就不允许其他事务获得该记录的X锁
读取时加X锁:
SELECT.... for update:为这条记录加了X锁后,就不允许其他事务获得该记录的S、X锁.
锁定写操作
写操作只有三种:delete、update、insert对于delete操作:获取记录位置,然后获取它的X锁,再进行deletemark操作----可以理解为获取X的锁定读对于update操作:
获取记录位置,相当于获取X锁,锁定读。然后主键更改,就删除,并重新添加一个,如果没更改,就直接在原记录中更新.对于insert操作:
并不加锁.有隐式锁来保护不被其他事务打扰.
表锁
表锁会锁住整张表,是MySQL中最基本的锁策略,并且不依赖于任何存储引擎.
表级别的S、X锁.
- 对表执行普通的增加删除修改更新操作时,不会添加表级的S、X锁.
- 当事务A对表执行增加删除修改更新操作,事务B并发执行影响表结构的操作(如
alter table
、drop table
)时,才会有表级锁的出现,对事务进行阻塞 - 同理,事务A对表结构进行修改时,如果事务B并发执行普通的增删查改,也会发生阻塞.
为表添加S、X锁
LOCK TABLES T read;LOCK TABLES t WRITE;虽然可以手动添加表锁,但一般很少使用,因为有更强大的行锁
限制关系
对限制关系的演示
初始化数据
mysql> create table mylock(-> id int not null primary key auto_increment,-> name varchar(20)-> )engine myisam;
Query OK, 0 rows affected (0.06 sec)mysql> insert into mylock(name) values('a');
Query OK, 1 row affected (0.04 sec)加锁
mysql> lock tables mylock read;
Query OK, 0 rows affected (0.00 sec)加锁后自己可读
mysql> select*from mylock;
+----+------+
| id | name |
+----+------+
| 1 | a |
+----+------+
1 row in set (0.00 sec)自己不可写
mysql> update mylock set name='a1' where id=1;
## ERROR 1099 (HY000): Table 'mylock' was locked with a READ lock and can't be updated;#自己不可操作其他表
mysql> select *from account;
## ERROR 1100 (HY000): Table 'account' was not locked with LOCK TABLES他人可读
mysql> select* from mylock;
+----+------+
| id | name |
+----+------+
| 1 | a |
+----+------+
1 row in set (0.00 sec)
他人不可写 会阻塞
mysql> update mylock set name='a2' where id=1;释放锁
mysql> unlock tables ;
Query OK, 0 rows affected (0.00 sec)改为写锁
mysql> lock tables mylock write;
Query OK, 0 rows affected (0.00 sec)自己可以读取
mysql> select*from mylock;
+----+------+
| id | name |
+----+------+
| 1 | a |
+----+------+
1 row in set (0.00 sec)
自己可以写入
mysql> update mylock set name='a3' where id=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
自己不能操作其他表
mysql> select*from account;
ERROR 1100 (HY000): Table 'account' was not locked with LOCK TABLES他人读取会阻塞
mysql> select*from mylock;
## 阻塞
他人写入会阻塞
mysql> update mylock set name='a4' where id=1;
## 阻塞
意向锁.
事务A对某一行数据加了一个锁,事务B如果想对整张表加一个锁,就需要检查该表中是否已经存在锁,在数据量非常大的情况下,一页一页的检索是非常复杂的一件事情.此时就可以用到意向锁.
- 意向锁是表级别的锁,对整张表添加
- 意向锁是存储引擎自动添加,不需要手动添加
- 意向锁不会与行锁发生冲突
- 意向锁分两种:意向共享锁、意向排他锁
- 如果我们给某一行数据加上了排他锁,数据库会自动给更大一级的空间(比如数据页、数据表)加上意向锁,告诉他人这个数据页或数据表已经有人上过排他锁了
意向共享锁(IS锁)
存在事务想对表中的某个数据添加共享锁
--事务想要获取某项行的S锁,必须先获得表的IS锁
select...from table...lock in share mode;
意向排他锁(IX锁)
存在事务想对表中的某个数据添加排他锁
---事务想要获得某项行的X锁,必须先获得表的IX锁
select ... from table...for update;
- 意向锁之间相互兼容,互不影响
- 意向锁和表级别的X,S锁不兼容,除了IS和S
自增锁
- 特殊的表级锁,事务向
AUTO_INCREMENT
字段添加新数据时就会持有自增锁 - 如果事务A正在向自增列添加新数据,此处事务B尝试
INSERT
,就会被阻塞. - 不同锁模式下运行机制不同,行为不同,锁模式通过参数
innodb_autoinc_lock_mode
进行设置 - 自增列必须是索引才能用自增锁.
元数据锁
- 元数据锁(
meta data lock
,MDL锁)是表锁. - 当事务对一个表进行增删改查时,会自动添加MDL读锁,当事务对表结构进行修改的时候,会自动添加MDL写锁
- 自动添加MDL锁的作用就是防止表在增删改时,表结构被改动。
- 读读不互斥、读写、写写互斥
- 自动添加,无须手动
行锁
- 对某一条记录进行加锁
- 优势是锁定单位小,所以冲突概率低,并发性非常高,劣势是会用太多的锁资源,加锁慢,容易出现死锁问题
- Innodb和MyISAM引擎最大的不同:支持事务;支持行锁
记录锁
- 非常普通的锁,就是对某一条记录加锁
- 分为S、X型。
- 当事务获的某条记录的S型记录锁后,其他事务只能获取S型
- 当事务获得某条记录的X型锁后,其他事务只能等待
间隙锁
- 我们可以通过加锁的方式解决幻读问题,但是问题是幻读产生的那些幻影记录一开始并不存在,无法加锁,为了解决这个问题,就产生了间隙锁(
gap锁
) - 间隙锁只有一个作用:防止插入幻影记录
- 比如我们对id=8的记录加上间隙锁,那么上一条记录和id=8的记录之间就不允许插入新的记录,如果其他事务想要插入新的记录,会被阻塞.
- 对某记录之后的区间加上gap锁,需要用两条伪记录:
Infimum
记录,表示该页中最小记录;Supremum
记录,表示该页中最大的记录; - 直接对
Supremum
记录加gap锁即可
临键锁
- 临键锁=记录锁+间隙锁
- 作用:锁住某条记录,并阻止其他事务在该事务前面的间隙插入事务
- 分为临键S和临键X锁,互斥情况和记录锁相同
begin;
select*from student where id<=8 and id>3 for update;
插入意向锁
- 插入意向锁是在插入一条记录时,由
INSERT
操作产生的一种间隙锁. - 插入意向锁本质是间隙锁
- 在插入一条记录时,需要看插入位置是否被别的事务加了间隙锁,如果有,需要等待,知道间隙锁的事物提交.等待时,会生成一个锁结构,表名某事务有在某位置插入数据的意图,这个锁结构就是意向锁
- 插入意向锁互不排斥
当事务T1结束后,事务T2和T3都会获取到插入意向锁:
页锁
- 粒度大小介于表锁和行锁之间
- 开销介于表锁和行锁之间
- 锁的空间大小有限,超过大小时,会自动进行锁升级.
粒度越大,开销越小。粒度大小:表>页>行。开销:表<页<行
其他锁
全局锁
- 对整个数据库实例加锁,整个库处于只读的状态
- 增删查改、修改表结构的等都会阻塞
- 使用场景:全库备份(对数据库进行备份时,不允许操作)
- 命令:
Flush tables with read lock
死锁
- 两个或多个事务在同一资源上进行占用,都有对方的需要的锁,但都不释放,陷入死循环
- 例如下图:事务1对id=1的记录设置了X锁,事务2又对id=2的记录设置了X锁。事务1在尝试更新记录2时陷入阻塞,事务2再尝试更新记录1时陷入阻塞。然后两个事务互相僵持,陷入死锁状态
死锁条件
- 必须有两个事务
- 每个事务都持有锁,还申请新的锁
- 新锁恰好为对方所有
如何处理死锁
方法1:等待,直到超时
两个事务互相等待,当一个事务等待时间超过设置的阈值时,就将其回滚。另一个事务就可以继续进行。
Innodb中,使用
innodb_lock_wait_timeout
设置时间方法2:使用死锁检测进行死锁处理
innodb中有wait-for graph算法主动检测死锁,每次加锁需要等待时就会触发
死锁检测原理:
数据库会保存锁的信息链表
和事务等待链表
根据上面两个信息,可以画出等待有向图:
在等待图中,如果有环的存在,就是死锁。
- 如果出现死锁,存储引擎就会回滚
操作量最小的事务
.
MySQL~锁的大集合(S锁、X锁、意向锁、自增锁、元数据锁、记录锁、间隙锁、临键锁、全局锁、死锁)相关推荐
- MySQL锁:全局锁、表级锁和行锁
事务的实现离不开MySQL数据库的锁机制,设计锁的目的也是为了处理并发访问问题,本文简单介绍MySQL 里面的全局锁.表级锁和行锁三类锁. 目录 全局锁 表级锁 表锁 1.读锁实例 2.写锁实例 元数 ...
- mysql锁(全局锁、表锁、行锁、页锁、排他锁、共享锁)
mysql锁 简介 数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则. MySQL数据库由于其自身架构的特点,存在多种数据存储引擎,每种存储 ...
- mysql进阶: mysql中的锁(全局锁/表锁/行锁/间隙锁/临键锁/共享锁/排他锁)
锁在生活中处处可见,门锁,手机锁等等. 锁存在的意义是保护自己的东西不被别人偷走/修改. 在mysql中锁的意义也是一样,是为了保护自己的数据不被别人进行修改,从而导致出现脏读,幻读等问题.在学习锁的 ...
- mysql主键查询gap锁失效,mysql记录锁(record lock),间隙锁(gap lock),Next-key锁(Next-key lock)...
1. 什么是幻读? 幻读是在可重复读的事务隔离级别下会出现的一种问题,简单来说,可重复读保证了当前事务不会读取到其他事务已提交的 UPDATE 操作.但同时,也会导致当前事务无法感知到来自其他事务中的 ...
- mysql 写锁需要等待读锁释放吗_Mysql实战45讲笔记:5、全局锁和表锁
全局锁: 对整个数据库实例加锁. MySQL提供加全局读锁的方法:Flush tables with read lock(FTWRL) 这个命令可以使整个库处于只读状态.使用该命令之后,数据更新语句. ...
- mysql主键更新被锁_MySQL 的加锁处理,你都了解的一清二楚了吗?
MySQL加锁分析,一直是一个比较困难的话题. 我在工作过程中,经常会有同事咨询这方面的问题.本文,准备就MySQL加锁问题,展开较为深入的分析与讨论,主要是介绍一种思路,运用此思路,拿到任何一条SQ ...
- mysql是表级锁还是行级锁_带你了解MySQL数据库中的全局锁、表级锁、行级锁
在 MySQL 数据库中,有很多各种各样的锁,这些锁大致可以分为三类:全局锁.表级锁.行级锁.这篇文章小编就带你简单了解一下这三种锁. 1. 全局锁 全局锁是粒度比较大的锁,基本上也使用不上,就像我们 ...
- mysql 锁 行级_全局锁、表级锁、行级锁mysql 极客评论笔记
根据加锁范围:MySQL里面的锁可以分为: 一.全局锁: 对整个数据库实例加锁. MySQL提供加全局读锁的方法:Flush tables with read lock(FTWRL) 这个命令可以使整 ...
- mysql全局读写怎么锁_MySQL全局锁和表锁
最近正好在看操作系统中关于线程,锁的部分,也可以学习一下数据库种的锁. MySQL的锁分为全局锁,表级锁,行锁三类. 全局锁 名思义,全局锁就是对整个数据库实例加锁.MySQL提供了一个加全局读锁的方 ...
- Mysql 全局锁入门
全局锁顾名思义,全局锁就是对整个数据库实例加锁. 如何手动使用全局锁? MySQL 提供了一个加全局读锁的方法,命令是 Flush tables with read lock (FTWRL).当你需要 ...
最新文章
- Contact Bubble View
- C# cs文件表头模版
- springboot 集成rabbitmq 实例
- socket认证客户端链接合法性
- 数据结构(一)线性表链式存储实现
- 对C# 程序员来说现在是到目前为止最好的时代
- antd autoplay按f12才会轮播_涨知识了!原来这才是电脑键盘上,F1到F12的正确用法...
- java源码如何启动脚本_使用Shell脚本如何启动/停止Java的jar程序
- 日常的SQL 语句使用
- java收_收java的小程序……谢谢
- Qt数据可视化(QPieSeries饼状图)
- 【源码阅读 | 03】only-allow 统一规范团队包管理器
- 学嵌入式为什么要学Linux?
- 【AD】原理图放置差分对,报错Missing Negative Net for differential pair
- 嵌入式课程设计linux,嵌入式课程设计报告
- Cannot find ./catalina.sh The file is absent or does not hav
- 一台机子上运行多个mysql实例
- POI 设置单元格背景色,背景色编码与实际颜色对照表(SXSSFWorkbook4.1.2)
- 图片中的alt标签和title标签
- 微信多平台版本日志大全.2021-12-17