环境准备
数据库隔离级别:
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 的锁时,会做如下处理:
- T2 请求 s 锁立即被允许,结果 T1 T2 都持有 r 行的 s 锁
- T2 请求 x 锁不能被立即允许
如果 T1 持有 r 的 x 锁,那么 T2 请求 r 的 x、s 锁都不能被立即允许,T2 必须等待T1释放