一、什么是死锁
- 1.必须满足的条件
1. 必须有两个或者两个以上的事务
2. 不同事务之间都持有对方需要的锁资源。 A事务需要B的资源,B事务需要A的资源,这就是典型的AB-BA死锁
- 2.死锁相关的参数
* innodb_print_all_deadlocks
1. 如果这个参数打开,那么死锁相关的信息都会打印输出到error log
* innodb_lock_wait_timeout
1. 当MySQL获取row lock的时候,如果wait了innodb_lock_wait_timeout=N的时间,会报以下错误
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
* innodb_deadlock_detect
1. innodb_deadlock_detect = off 可以关闭掉死锁检测,那么就发生死锁的时候,用锁超时来处理。
2. innodb_deadlock_detect = on (默认选项)开启死锁检测,数据库自动回滚
* innodb_status_lock_output = on
1. 可以看到更加详细的锁信息
二、死锁有什么危害
- 死锁,即表明有多个事务之间需要互相争夺资源而互相等待。
- 如果没有死锁检测,那么就会互相卡死,一直hang死
- 如果有死锁检测机制,那么数据库会自动根据代价来评估出哪些事务可以被回滚掉,用来打破这个僵局
- 所以说:死锁并没有啥坏处,官网:www.fhadmin.org 反而可以保护数据库和应用
- 那么出现死锁,而且非常频繁,我们应该调整业务逻辑,让其避免产生死锁方为上策
三、典型的死锁案例剖析
3.1 死锁案例一
典型的 官网:www.fhadmin.org AB-BA 死锁
session 1:
select * from tb_b where id_2 = 1 for update (A)
session 2:
select * from tb_a where id = 2 for update (B)
session 1:
select * from tb_a where id = 2 for update (B)
session 2:
select * from tb_b where id_2 = 1 for update (A)
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
1213的死锁错误,mysql会自动回滚
哪个回滚代价最小,回滚哪个(根据undo判断)
------------------------
LATEST DETECTED DEADLOCK
------------------------
2017-06-22 16:39:50 0x7f547dd02700
*** (1) TRANSACTION:
TRANSACTION 133601982, ACTIVE 48 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 4 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 11900, OS thread handle 140000866637568, query id 25108 localhost dba statistics
select * from tb_a where id = 2 for update -----session1 持有tb_a中记录为2的锁
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 303 page no 3 n bits 72 index PRIMARY of table `lc_5`.`tb_a` trx id 133601982 lock_mode X locks rec but not gap waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 4; hex 80000002; asc ;; --session 1 需要tb_a中记录为2的锁( session1 -> session2 )
1: len 6; hex 000007f69ab2; asc ;;
2: len 7; hex dc000027100110; asc ' ;;
*** (2) TRANSACTION:
TRANSACTION 133601983, ACTIVE 28 sec starting index read, thread declared inside InnoDB 5000
mysql tables in use 1, locked 1
4 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 11901, OS thread handle 140000864773888, query id 25109 localhost dba statistics
select * from tb_b where id_2 = 1 for update
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 303 page no 3 n bits 72 index PRIMARY of table `lc_5`.`tb_a` trx id 133601983 lock_mode X locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 4; hex 80000002; asc ;; --session 2 持有tb_a中记录等于2的锁
1: len 6; hex 000007f69ab2; asc ;;
2: len 7; hex dc000027100110; asc ' ;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 304 page no 3 n bits 72 index PRIMARY of table `lc_5`.`tb_b` trx id 133601983 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 4; hex 80000001; asc ;; --session 2 需要tb_b中记录为1的锁 ( session2 -> session1 )
1: len 6; hex 000007f69ab8; asc ;;
2: len 7; hex e0000027120110; asc ' ;;
最终的结果:
死锁路径:[session1 -> session2 , session2 -> session1]
ABBA死锁产生
3.2 死锁案例二
同一个事务中,官网:www.fhadmin.org S-lock 升级为 X-lock 不能直接继承
* session 1:
mysql> CREATE TABLE t (i INT) ENGINE = InnoDB;
Query OK, 0 rows affected (1.07 sec)
mysql> INSERT INTO t (i) VALUES(1);
Query OK, 1 row affected (0.09 sec)
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM t WHERE i = 1 LOCK IN SHARE MODE; --获取S-lock
+------+
| i |
+------+
| 1 |
+------+
* session 2:
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> DELETE FROM t WHERE i = 1; --想要获取X-lock,但是被session1的S-lock 卡住,目前处于waiting lock阶段
* session 1:
mysql> DELETE FROM t WHERE i = 1; --想要获取X-lock,session1本身拥有S-lock,但是由于session 2 获取X-lock再前,所以session1不能够从S-lock 提升到 X-lock,需要等待session2 释放才可以获取,所以造成死锁
ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction
死锁路径:
session2 -> session1 , session1 -> session2
3.3 死锁案例三
唯一键死锁 (delete + insert)
关键点在于:S-lock
dba:lc_3> show create table uk;
+-------+--------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+--------------------------------------------------------------------------------------------------------------+
| uk | CREATE TABLE `uk` (
`a` int(11) NOT NULL,
UNIQUE KEY `uniq_a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------+--------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
dba:lc_3> select * from uk;
+---+
| a |
+---+
| 1 |
+---+
1 row in set (0.00 sec)
session 1:
dba:lc_3> begin;
Query OK, 0 rows affected (0.00 sec)
dba:lc_3> delete from uk where a=1;
Query OK, 1 row affected (0.00 sec)
session 2:
dba:(none)> use lc_3;
Database changed
dba:lc_3> insert into uk values(1); --wait lock(想要加S-lock,却被sesson1的X-lock卡住)
sesson 3:
dba:(none)> use lc_3;
Database changed
dba:lc_3> insert into uk values(1); --wait lock(想要加S-lock,却被sesson1的X-lock卡住)
session 1:
commit; --session2和session3 都获得了S-lock,然后都想要去给记录1 加上X-lock,却互相被对方的S-lock卡住,死锁产生
再来看session 2 和 session 3 的结果:
session2:
Query OK, 1 row affected (7.36 sec)
session3:
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
总结: 试想想,如果session 1 不是commit,而是rollback会是怎么样呢? 大家去测测就会发现,结果肯定是唯一键冲突啊
3.4 死锁案例四
主键和二级索引的死锁
* primary key
1 2 3 4 --primary key col1
10 30 20 40 --idx_key2 col2
100 200 300 400 --idx_key3 col3
* idx_key2 select * from t where col2 > 10: 锁二级索引顺序为:20 =》30 , 对应锁主键的顺序为:3 =》2
10 20 30 40
1 3 2 4
* idx_key3 select * from t where col3 > 100:锁二级索引顺序为:200 =》300 , 对应锁主键的顺序为:2 =》3
100 200 300 400
1 2 3 4
死锁路径:
由于二级索引引起的主键加锁顺序: 3 =》2
由于二级索引引起的主键加锁顺序: 2 =》3
这个要求并发,且刚好
session 1 加锁3的时候 session 2 要加锁2.
session 1 加锁2的时候 session 3 要加锁3.
这样就产生了 AB-BA 死锁
3.5 死锁案例五
purge + unique key 引发的死锁
A表的记录: id = 1 10 40 100 200 500 800 900
session 1 :
delete from a where id = 10; ???
session 2 :
delete from a where id = 800; ???
session 1 :
insert into a select 800; ???
session 2 :
insert into a select 10; ???
* 如果大家去跑这两钟SQL语句的并发测试,是可以导致死锁的。
* 如何验证是由于purge导致的问题呢?这个本想用mysqld-debug模式去关闭purge线程,但是很遗憾我没能模拟出来。。。
3.6 死锁案例六
REPLACE INTO问题
* 这个问题模拟起来非常简单,原理非常复杂,这里不过多解释
* 详情请看姜老师的文章,据说看懂了年薪都100w了: http://www.innomysql.com/26186-2/
* 解决方案:
* 用insert into ... on duplicate key update 代替 replace into
* 此方案亲测有效
四、如何避免死锁
- 产生死锁的原因
1. 事务之间互相占用资源
- 方法和总结
1. 降低隔离级别,修改 RR -> RC , 如果这个调整了,可以避免掉60%的死锁场景和奇怪的锁等待
2. 调整业务逻辑和SQL,让其都按照顺序执行操作
3. 减少unique索引,大部分死锁的场景都是由于unique索引导致
4. 尽量不用replace into,用insert into ... on duplicate key update 代替
相关推荐
当多个事务请求对同一资源进行访问时,可能会出现等待的情况,即一个事务正在等待另一个事务释放锁,而后者也在等待前者释放锁,这种现象被称为“死锁”。为了保证数据的一致性和完整性,Oracle数据库提供了一系列...
MySQL的InnoDB存储引擎在处理死锁问题上采用了一系列策略,确保数据库的正常运行和高并发性能。首先,我们需要理解什么是死锁。死锁是指两个或多个事务在执行过程中,因争夺资源而造成的一种相互等待的现象,若无...
MySQL是世界上最受欢迎的关系型数据库管理系统之一,特别是在互联网行业中,它被广泛用于存储和管理大量数据。鲁班学院的这份课堂笔记深入浅出地探讨了MySQL中的核心概念:B+树索引、事务处理以及锁定机制。 一、...
MySQL 中有表级锁、行级锁和页面锁三种锁。表级锁开销小,加锁快,锁定粒度大,发生锁冲突的概率最高,并发度最低。行级锁开销大,加锁慢,锁定粒度最小,发生锁冲突的概率最低,并发度也最高。页面锁的开销和加锁...
1. **InnoDB存储引擎增强**:MySQL 5.5默认使用InnoDB存储引擎,它增强了并发性能,支持更多的锁粒度,降低了死锁的可能性。此外,InnoDB表空间的初始大小和自动扩展功能也得到了优化。 2. **性能优化**:引入了更...
在优化与执行阶段,MySQL会解析查询,构建内部数据结构,并进行一系列优化,包括重写查询、选择索引等。 并发控制是数据库高效运行的关键。MySQL支持读锁和写锁,以及不同粒度的锁,如表锁和行级锁。行级锁能提高...
文档中可能讨论了不同类型的锁(例如,行锁和表锁)以及如何避免锁争用,减少死锁的发生。 4. 优化server:这部分涉及如何对MySQL服务器进行配置和优化。例如,优化查询缓存、调整表和索引的存储引擎参数、调整内存...
总的来说,MySQL的事务处理机制包括了对事务的开启、提交、回滚以及自动提交的控制,同时还提供了行级锁来保证并发操作时的数据一致性。理解并正确使用这些机制是确保数据库稳定性与数据完整性的关键。
它的事务处理机制、锁策略以及多版本并发控制技术,构成了MySQL数据库的核心技术之一。DBA需要对这些知识点有深入的理解和掌握,才能有效地管理维护数据库系统,优化系统性能,确保数据的安全性和一致性。
MySQL通过死锁检测和超时机制解决,InnoDB存储引擎会检测到循环依赖并回滚持有最少行级排他锁的事务来打破死锁,必要时回滚事务以恢复系统。 5. **事务** 事务是一系列原子性的操作,要么全部成功提交,要么全部...
MySQL是世界上最受欢迎的关系型数据库管理系统之一,尤其在Web应用程序中被广泛应用。本学习资料全面涵盖了MySQL的基础知识到高级特性,包括深入理解、性能优化、分布式存储、缓存管理以及锁机制等多个方面,旨在...
教程将涵盖行级锁、表级锁、读写锁以及死锁检测和避免。 七、复制与集群 MySQL的复制技术用于数据冗余和故障恢复,而集群则能提供高可用性和负载均衡。caoz会讲解主从复制的配置和优化,以及MySQL集群的实现方式。 ...
MySQL 5.7.19 是 MySQL 数据库管理系统的一个重要版本,它在5.7系列中引入了许多增强功能和性能优化。以下是对该版本数据库安装包的详细解析: 1. **MySQL 5.7版本概述**: MySQL 5.7是MySQL的一个重大更新,特别...
MySQL是世界上最受欢迎的关系型数据库管理系统之一,尤其在Web应用程序中广泛应用。本进阶资料主要涵盖了在Linux操作系统上安装MySQL以及一系列高级主题,旨在提升你对MySQL的理解和操作能力。 首先,我们来了解...
5.5.29 版本进一步优化了锁机制,减少了死锁,提高了并发性能。同时,InnoDB 表现在内存管理和表空间管理上也有改进。 3. **Full-text Search 改进**:MySQL 5.5 引入了全文本搜索功能的增强,包括支持短语搜索和对...
- **多个锁的获取**:在复杂的操作场景下,可能需要获取多个表的元数据锁,这需要考虑锁之间的依赖关系以及死锁的可能性。 - **ALTER TABLE命令的锁升级场景**:在执行ALTER TABLE命令时,可能会涉及从共享元数据锁...
该教程由辛星编写,旨在帮助读者在已有基础之上进一步提升MySQL数据库应用能力,尤其是在视图、触发器、存储过程、事务、锁机制及存储引擎等方面的知识。 视图是数据库中非常重要的一个概念,它是一个虚拟的表,...