死锁-学习

141 阅读1分钟

1、数据准备

# age为普通索引
​
mysql> select * from user;
+----+----------+------+
| id | username | age  |
+----+----------+------+
|  1 | 小a      |   10 |
|  7 | 小b      |   10 |
|  8 | 小c      |   10 |
|  9 | 小d      |   20 |
| 10 | 小e      |   20 |
| 11 | 小f      |   20 |
| 12 | 小g      |   30 |
| 15 | 小h      |   30 |
| 20 | 小i      |   30 |
| 56 | 小j      |   40 |
| 58 | 小k      |   40 |
| 65 | 小l      |   50 |
| 66 | 小m      |   60 |
+----+----------+------+

2、间隙锁导致死锁demo

【view1】
​
步骤一: 更新age=20的字段
set autocommit = 0;
START TRANSACTION;
--  增加间隙锁,范围是age (10,30)
UPDATE user SET age = 200 WHERE age = 20; 
​
步骤三:新建age=30的数据,一直等待 view2 释放间隙锁
INSERT into `user` (username,age) VALUES("小壮",30);
​
​
​
【view2】
步骤二:更新age=30的字段
set autocommit = 0;
START TRANSACTION;
-- 增加间隙锁,范围是age (20,40)
UPDATE user SET age = 300 WHERE age = 30; 
​
步骤四:新建age=20的数据,需要 view1 释放间隙锁,这时发现死锁了, view2进行事物回滚,步骤三插入成功 
-- Deadlock found when trying to get lock; try restarting transaction
INSERT into `user` (username,age) VALUES("小焦",20);
​

3、如何避免死锁

  • 大事物变小事物
  • 尽量通过唯一索引进行更新,防止大范围间隙锁产生;没有索引的话会锁全表