Mysql 死锁

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 在高并发情况下,不同事务持有资源而等待另一个资源锁时,而其他事务恰好相反,出现了循环等待,即出现了死锁。

在高并发情况下,不同事务持有资源而等待另一个资源锁时,而其他事务恰好相反,出现了循环等待,即出现了死锁。
一般的,最常见且最易理解的死锁形式是:
事务T1持有A的锁->等待B的锁
事务T2持有B的锁->等待A的锁
这样的形式即发生了死锁,后续会介绍死锁避免及死锁解决,现在来看看对同一个行操作,mysql是如何出现死锁了。

首先,T1进行

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT id FROM pet where id=10 for share;
+----+
| id |
+----+
| 10 |
+----+
1 row in set (0.00 sec)

T2进行

START TRANSACTION;
DELETE from pet where id=10;
##会提示
DELETE from pet where id=10;
[Err] 1205 - Lock wait timeout exceeded; try restarting transaction

因为T1不是自动提交事务,查询的时候,hold持有共享锁,而此时T2开启事务并试图进行delete拿x锁,但处于一直等待中,当最后等待锁超时而自动放弃(innodb-lock-wait-timeout 默认是50s)。

做一下调整,如果T2还在等待T1释放锁时,T1进行同样的删除操作
T1:

mysql> DELETE from pet where id=10;
Query OK, 1 row affected (0.00 sec)

此时 T2:

DELETE from pet where id=10;
[Err] 1213 - Deadlock found when trying to get lock; try restarting transaction

过程:如果T1开启事务,先拿取了记录R的S读锁,此时T2来删除R需要用X锁,因T1占有S锁不得不等待,在此等待过程中,T1又进行了删除操作又尝试对R记录追加X锁,最后导致T2发生死锁退出。

死锁原因:
此处发生死锁,因为客户端T1需要X锁来删除该行。 但是,无法授予该锁请求,因为客户端T2已经有一个X锁请求并且正在等待客户端T1释放其S锁。 由于T2先前对X锁的请求,T1保持的S锁也不能升级到X锁。 因此,InnoDB会为其中一个客户端生成错误并释放锁。

启用死锁检测(默认设置)后,InnoDB会自动检测事务死锁并回滚事务或事务以打破死锁。 InnoDB尝试选择要回滚的小事务,其中事务的大小由插入,更新或删除的行数决定。
innodb-deadlock-detect[={OFF|ON}] 死锁检测,默认值为ON

如果innodb_table_locks = 1(默认值)和autocommit = 0,InnoDB知道表锁,并且它上面的MySQL层知道行级锁。否则,InnoDB无法检测到由MySQL LOCK TABLES语句设置的表锁或由InnoDB以外的存储引擎设置的锁的死锁。通过设置innodb_lock_wait_timeout系统变量的值来解决这些情况。

当InnoDB执行事务的完全回滚时,将释放由事务设置的所有锁。但是,如果由于错误而仅回滚单个SQL语句,则可能会保留由该语句设置的某些锁定。发生这种情况是因为InnoDB以一种格式存储行锁,以至于后来无法知道哪个锁由哪个语句设置。

如果SELECT在事务中调用存储的函数,并且函数中的语句失败,则该语句将回滚。此外,如果在此之后执行ROLLBACK,则整个事务回滚。

禁用死锁检测
在高并发系统上,当许多线程等待同一个锁时,死锁检测会导致速度减慢。有时,在发生死锁时,禁用死锁检测并依赖innodb_lock_wait_timeout设置进行事务回滚可能更有效。可以使用innodb_deadlock_detect配置选项禁用死锁检测。

使用以下技术处理死锁并降低其发生的可能性:
●在任何时候,发出SHOW ENGINE INNODB STATUS命令以确定最近死锁的原因。这可以帮助您调整应用程序以避免死锁。

●如果频繁出现死锁警告,请通过启用innodb_print_all_deadlocks配置选项来收集更多的调试信息。有关每个死锁的信息,而不仅仅是最新的死锁,都记录在MySQL错误日志中。完成调试后禁用此选项。

●如果由于死锁而失败,请始终准备重新发布事务。死锁并不危险。再试一次。

●保持交易持续时间短且不易发生,以减少交易。

●在进行一组相关更改后立即提交事务,以使它们不易发生冲突。特别是,不要使用未提交的事务使交互式mysql会话长时间保持打开状态。

●如果使用锁定读取(SELECT ... FOR UPDATE或SELECT ... FOR SHARE),请尝试使用较低的隔离级别,例如READ COMMITTED。

●在事务中修改多个表或同一个表中的不同行集时,每次都以一致的顺序执行这些操作。然后事务形成定义良好的队列,不会死锁。例如,将数据库操作组织到应用程序中的函数中,或调用存储的过程,而不是在不同的位置编写多个类似的INSERT,UPDATE和DELETE语句序列。

●在表中添加精心选择的索引。然后,您的查询需要扫描更少的索引记录,从而设置更少的锁。使用EXPLAIN SELECT确定MySQL服务器认为哪些索引最适合您的查询。

●使用较少的锁。如果您能够允许SELECT从旧快照返回数据,请不要向其添加FOR UPDATE或FOR SHARE子句。在这里使用READ COMMITTED隔离级别很好,因为同一事务中的每个一致读取都从其自己的新快照读取。

●如果没有其他帮助,请使用表级锁定序列化您的事务。将LOCK TABLES用于事务表(如InnoDB表)的正确方法是使用SET autocommit = 0(不是START TRANSACTION)后跟LOCK TABLES开始事务,并且在显式提交事务之前不调用UNLOCK TABLES。例如,如果需要写入表t1并从表t2读取,则可以执行以下操作:

SET autocommit = 0;
LOCK TABLES t1 WRITE,t2 READ,...;
...... do something with tables t1 and t2 here......
COMMIT;
UNLOCK TABLES;

表级锁可防止对表的并发更新,从而避免死锁,但代价是对繁忙系统的响应性较低。

●序列化事务的另一种方法是创建一个只包含一行的辅助“信号量”表。让每个事务在访问其他表之前更新该行。这样,所有事务都以串行方式发生。请注意,InnoDB即时死锁检测算法在这种情况下也适用,因为序列化锁是一个行级锁。使用MySQL表级锁定时,必须使用超时方法来解决死锁。

补:
你可以在my.ini配置文件中,使用innodb_read_io_threads和innodb_write_io_threads配置参数来配置为数据页读写I/O提供服务的后台线程的数量。这些参数表示用于读写请求的后台线程的数量。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3月前
|
算法 关系型数据库 MySQL
MySQL相关(九)- 死锁的发生和避免
MySQL相关(九)- 死锁的发生和避免
25 0
|
3月前
|
SQL 关系型数据库 MySQL
MySQL事务原理分析(ACID特性、隔离级别、锁、MVCC、并发读异常、并发死锁以及如何避免死锁)
MySQL事务原理分析(ACID特性、隔离级别、锁、MVCC、并发读异常、并发死锁以及如何避免死锁)
86 1
|
4月前
|
关系型数据库 MySQL 调度
KnowStreaming系列教程第四篇——MySQL数据更新死锁问题
KnowStreaming系列教程第四篇——MySQL数据更新死锁问题
42 0
|
4月前
|
SQL 存储 关系型数据库
MySQL 意向共享锁、意向排他锁、死锁
MySQL 意向共享锁、意向排他锁、死锁
47 0
MySQL 意向共享锁、意向排他锁、死锁
|
9月前
|
SQL 监控 算法
MySQL锁定:死锁及其避免方法
MySQL锁定:死锁及其避免方法
|
5月前
|
SQL NoSQL 关系型数据库
Mysql Innodb死锁情况分析与归纳
Mysql Innodb死锁情况分析与归纳
50 0
|
11月前
|
SQL 关系型数据库 MySQL
MySQL - 锁等待及死锁初探
MySQL - 锁等待及死锁初探
122 0
|
6月前
|
存储 SQL 关系型数据库
MySQL 优化 index merge(索引合并)引起的死锁分析(强烈推荐)
生产环境出现死锁流水,通过查看死锁日志,看到造成死锁的是两条一样的update语句(只有where条件中的值不同),如下:
|
6月前
|
SQL 关系型数据库 MySQL
Mysql死亡笔记的死锁记录
Mysql死亡笔记的死锁记录
67 0
|
6月前
|
关系型数据库 MySQL 中间件
MySQL学习笔记-死锁和死锁检测
MySQL学习笔记-死锁和死锁检测
50 0