MySQL 锁全解:从行锁到死锁,一文讲透所有面试考点
在MySQL中,锁是实现并发控制的一种机制,用于管理对数据库中数据的访问。MySQL支持多种类型的锁,包括表锁和行锁。行锁是较为先进的锁机制,因为它允许多个事务同时对数据库中的不同行进行操作,从而提高并发性能。然而,如果不正确管理,即使是行锁也可能导致死锁。
行锁
行锁是MySQL中较为常见的一种锁机制,它允许多个事务对不同的行进行操作,而不会互相干扰。InnoDB存储引擎使用行锁来实现其多版本并发控制(MVCC)。
死锁
死锁是指两个或多个事务在执行过程中,因互相等待对方释放资源而无法继续执行的情况。例如,事务A持有资源B并请求资源C,同时事务B持有资源C并请求资源A。
避免死锁的策略
- 使用索引:确保涉及的所有表都有适当的索引,特别是那些在WHERE子句中使用的列。
- 锁定顺序:在应用中强制一致的锁定顺序。所有事务都应该以相同的顺序请求资源。例如,始终先锁定表A再锁定表B。
- 超时设置:设置InnoDB的
innodb_lock_wait_timeout参数,该参数定义了事务等待锁的最长时间。超过这个时间后,事务会自动回滚以避免死锁。
- 超时设置:设置InnoDB的
- 使用乐观锁或悲观锁:
- 悲观锁:在事务开始时立即获取所有需要的锁。适用于写操作较多的场景。
- 乐观锁:不使用锁,而是在更新数据前检查版本号或时间戳。适用于读多写少的场景。
- 检测和解决死锁:
- 使用
SHOW ENGINE INNODB STATUS命令查看死锁日志,分析死锁原因。 - 使用
INNODB_TRX,INNODB_LOCKS,INNODB_LOCK_WAITS表查询当前的事务和锁情况。
- 使用
mysql里有哪些锁?
在MYSQL里把锁分为三类:全局锁、表锁、行级锁
全局锁:在使用了flush tables with read lock语句之后,全库都会进入只读状态,数据库执行增删改和修改表结构的操作时,都会被阻塞;主要用于在全表进行备份时,防止其他事务修改表的数据
表级锁:
表锁:使用lock tables语句就会给表上锁,限制其他线程访问这张表,这里对线程有两种限制方式:
1.读锁 lock tables 表名 read
本线程:可读,不能写
其他线程:可读,不能写
2.写锁 lock tables 表名 write
本线程:可读可写
其他线程:读写全都阻塞
元数据锁:对表上一个MDL锁,如果是对表进行CRUD操作,会对表上MDL读锁,如果是修改表的结构,就会对表上一个MDL写锁,MDL锁的作用是防止线程在操作表时,其他线程影响表的结构和数据
意向锁:当执行插入、更新、删除操作,需要先对表加上「意向独占锁」,然后对该记录加独占锁。意向锁用于确定这个表是否有行级锁
两类意向锁:
- 意向共享 IS:后续要加共享行锁(S锁)
- 意向独占 IX:后续要加独占行锁(增删改都会触发、X锁)
行级锁:InnoDB 引擎是支持行级锁的,而 MyISAM 引擎并不支持行级锁。
记录锁(Record Lock):分为S读锁和X写锁,满足读写互斥和写写互斥
| 已有锁 | 加 S 锁 | 加 X 锁 |
|---|---|---|
| S 锁 | 允许 | 阻塞 |
| X 锁 | 阻塞 | 阻塞 |
间隙锁(Gap Lock):只存在于可重复读隔离级别,是为了解决可重复读(RR)隔离级别下的幻读现象。
临键锁(Next-key Lock):记录锁 + 间隙锁合体,会锁定一个范围,并锁定这个范围的数据
InnoDB有哪些锁呢:行级锁、表锁、意向锁
行锁什么时候变表锁?
这里不是有一个升级阈值一样的规定,所谓 “行锁变表锁”,是看起来像锁表,本质是锁了全表所有行 / 大范围间隙,效果等价于表锁。
InnoDB 行锁依托索引生效,无索引 / 索引失效时会全表扫描,行操作就会查询全表,然后给所有行加锁效果等价于表锁
临键锁怎么解决幻读?
因为临建锁 = 间隙锁 + 记录锁,利用这两个锁的机制就可以大幅度的减少幻读的发生
- 锁住查到的真实数据行(记录锁) 不让别人修改已有数据
- 锁住数据前后的空白间隙(间隙锁) 区间内无法插入新记录
- 范围查询会锁定一整个左开右闭区间 别的事务插不进区间空位,自然不会凭空多出数据,大幅规避幻读
什么是死锁?产生条件、怎么排查和避免死锁?
死锁定义:
两个事务互相持有对方的锁,并且自身不会主动释放锁,互相陷入等待的循环就是锁
产生条件:
- 互斥性:一把锁只有一个事务可以拿到
- 请求并保持:持有锁的同时去请求另一把锁
- 不可剥夺:锁不能被抢走,只能主动释放
- 循环等待:A等B的锁,B等A的锁
MySQL 排查死锁
查看最近死锁日志
show engine innodb status;
日志里看:阻塞 SQL、持有锁、等待锁、事务执行顺序,定位冲突语句
避免死锁:
- 统一访问顺序 :所有事务按相同顺序操作表、操作行,杜绝循环等待。
- 缩小事务范围 :事务尽量短小,尽早提交,减少锁持有时间。
- 合理使用索引 :保证更新语句走索引,锁定行数越少,锁冲突越少。
- 避免事务内等待交互 :不要事务中途等待用户操作、接口调用,防止长时间占锁。
总结:
主要是了解了mysql里面所有的锁的定义,行锁与表锁并不是字面意思上的转换,而是效果上在全盘扫描时实现了锁全表的现象,临键锁解决幻读,从临键锁的组成来分为锁数据(记录锁)和锁数据前后的空白间隙(间隙锁),以及死锁的相关知识。
到此这篇关于MySQL 锁全解:从行锁到死锁,一文讲透所有面试考点的文章就介绍到这了,更多相关mysql行锁到死锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Mysql连接本地报错:1130-host ... is not allowed to connect t
这篇文章主要给大家介绍了关于Mysql连接本地报错:1130-host ... is not allowed to connect to this MySQL server的解决方法,文中通过图文介绍的非常详细,需要的朋友可以参考下2023-03-03
MySQL count(*),count(id),count(1),count(字段)区别
本文主要介绍了MySQL count(*),count(id),count(1),count(字段)区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2023-05-05


最新评论