当前位置: 首页>后端>正文

MySQL 死锁怎么发生的?怎么解决?

引言:MySQL 死锁可能很多人都不会去了解,只了解操作系统的死锁和 Java 中的死锁,本文将会讲述面试中依然会遇到的重点部分,MySQL 死锁产生的原因和解决方案。

题目

MySQL 死锁怎么发生的?怎么解决?

推荐解析

死锁产生的原因

可重复读隔离级别,会有当前读的幻读问题。

所以 InnoDB 是采用了 MVCC + NextKey 锁,解决当前读的幻读问题。

NextKey(临键锁) = RecordLock(记录锁)+GapLock(间隙锁)。

记录锁:锁行记录本身,一条。

间隙锁:除锁记录本身,锁定一个范围,多条。

普通 Select 语句是属于当前读,不加行锁。

加行锁方式: share mode 共享锁(多个读可以,修改不行),或者 for update 直接加排他锁(独占)。

行锁的释放时机是在事务提交之后,也就是写入 binlog 日志,并且 redolog 是 Commit 状态,不是语句执行结束就释放行锁了,关键是事务什么时候提交。

锁是针对索引进行加锁,如果没有使用到索引,会进行全表扫描,就会产生业务宕机情况。

两个事务,都采用加行锁,并且由于加锁范围产生了交集,因此

就会产生等待,要注意 X 和 X,X 和 S,S 和 S,三个只有 S 和 S 可以共享,其他都会冲突阻塞。

死锁解决方案

1)设置事务等待锁的超时时间,超时后进行事务回滚,锁被释放,跟 Spring 的 @Transactional 的 timeOut 可以类比。

2)开启主动死锁检测,参数 InnoDB_deadlock_detect 设置为 on 开启,开启死锁检测。

最好在业务场景,直接杜绝死锁,比如接口幂等性,直接用分布式 id、唯一性索引、双重 token 等。

Insert 插入

在 MySQL 中,INSERT 语句并不会直接加行级锁。行级锁是在对数据进行读取或更新时加上的,以保护数据的一致性和完整性。然而,INSERT 语句可以触发行级锁的加锁行为,具体取决于数据库的隔离级别以及并发访问情况。

当执行 INSERT 语句时,如果插入的数据涉及到已经被其他事务锁定的行,则可能会发生行级锁定。这种情况下,MySQL 会根据当前事务的隔离级别和已经存在的锁情况来决定是否对相关行加锁,以确保数据的一致性和完整性。

在默认的隔离级别(REPEATABLE READ)下,当执行 INSERT 语句时,MySQL 会根据已有的锁情况来判断是否需要对相关行加锁。如果其他事务已经对插入的数据所在的行加了锁,MySQL 可能会等待该锁被释放后再执行插入操作,或者根据需要自动加锁。

其他补充

MySQL InnoDB 引擎下死锁产生的原因和解决方案

死锁产生的原因:

在 MySQL 的 InnoDB 引擎下,死锁(Deadlock)通常是由于多个事务相互竞争资源(例如行级锁)而产生的。当多个事务同时持有某些资源的锁,并且每个事务都在等待其他事务释放它所需的锁时,就会出现死锁。

死锁的解决方案:

  1. 超时重试: 当检测到死锁时,InnoDB 会选择其中一个事务作为死锁牺牲者,将其回滚并释放资源。其他事务会收到一个错误,可以在这种情况下重新尝试。
  2. 优化事务和锁定顺序: 通过优化事务的设计和锁定资源的顺序,可以减少死锁的发生。例如,尽量减少事务中涉及的数据量,避免长时间持有锁。
  3. 使用死锁检测工具: MySQL 提供了一些死锁检测工具,可以帮助识别和解决死锁问题。例如,通过设置 innodb_print_all_deadlocks=1 可以在日志中打印死锁信息。

数据库锁的种类和作用

在数据库中,锁是用来管理对共享资源的访问的机制。不同的锁具有不同的粒度和作用,常见的数据库锁包括:

  1. 行级锁(Row-level Lock): 行级锁用于锁定单个数据行,防止其他事务对该行进行修改。行级锁可以提高并发性,但可能会导致死锁问题。
  2. 表级锁(Table-level Lock): 表级锁用于锁定整个表,防止其他事务对整个表进行修改。表级锁会影响并发性,因为只有等到整个表解锁后,其他事务才能继续操作。
  3. 页级锁(Page-level Lock): 页级锁用于锁定数据页,即一组连续的数据行。它介于行级锁和表级锁之间,既提高了并发性,又减少了锁的粒度。
  4. 意向锁(Intention Lock): 意向锁是用来表示一个事务打算对某个资源(如表或页)加什么类型的锁。它不会阻止其他事务对资源加锁,只是为了协调其他事务对资源的锁定行为。
  5. 共享锁(Shared Lock)和排他锁(Exclusive Lock): 共享锁用于防止其他事务对资源进行写操作,但允许其他事务同时持有共享锁进行读操作;排他锁用于防止其他事务对资源进行读或写操作。

这些锁的作用是保护数据的一致性和完整性,确保在并发访问时数据不会被破坏或丢失。不同的锁适用于不同的场景,需要根据实际情况进行选择和使用。

欢迎交流

在阅读完本文后,你应该对死锁产生原因和解决方案有了一定的了解,首先需要知道 MySQL 锁的种类,以及各个所的作用,然后再根据不同的场景,去进行实践和分析,在文末还有三个问题,欢迎小伙伴在评论区发表见解!

1)死锁检测工具如何帮助解决 MySQL InnoDB 引擎下的死锁问题?它们是如何工作的?

2)在数据库设计中,如何优化事务和锁定资源的顺序以减少死锁的发生?能否给出一些实际案例或最佳实践?

3)行级锁、表级锁和页级锁各有什么优缺点?在什么情况下应该选择使用哪种锁?


https://www.xamrdz.com/backend/3h21934816.html

相关文章: