前言
前几天跟一位朋友分析了一个死锁问题,所以有了这篇图文详细的博文,哈哈~
发生死锁了,如何排查和解决呢?本文将跟你一起探讨这个问题准备好数据环境
模拟死锁案发
分析死锁日志
分析死锁结果
环境准备
数据库隔离级别:
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)
自动提交关闭:
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
| 0 |
+--------------+
1 row in set (0.00 sec)
表结构:
//id是自增主键,name是非唯一索引,balance普通字段
CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`balance` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
表中的数据:
模拟并发
开启两个终端模拟事务并发情况,执行顺序以及实验现象如下:
1)事务A执行更新操作,更新成功
mysql> update account set balance =1000 where name ='Wei';
Query OK, 1 row affected (0.01 sec)
2)事务B执行更新操作,更新成功
mysql> update account set balance =1000 where name ='Eason';
Query OK, 1 row affected (0.01 sec)
3)事务A执行插入操作,陷入阻塞~
mysql> insert into account values(null,'Jay',100);
这时候可以用 select * from information_schema.innodb_locks; 查看锁情况:
4)事务B执行插入操作,插入成功,同时事务A的插入由阻塞变为死锁error。
mysql> insert into account values(null,'Yan',100);
Query OK, 1 row affected (0.01 sec)
锁介绍
在分析死锁日志前,先做一下锁介绍,哈哈~
主要介绍一下兼容性以及锁模式类型的锁:
共享锁与排他锁
InnoDB 实现了标准的行级锁,包括两种:共享锁(简称 s 锁)、排它锁(简称 x 锁)。共享锁(S锁):允许持锁事务读取一行。
排他锁(X锁):允许持锁事务更新或者删除一行。
如果事务 T1 持有行 r 的 s 锁,那么另一个事务 T2 请求 r 的锁时,会做如下处理