主题
面试速答(先看这里)
**一句话结论:**为了避免这种死锁情况的发生,可以在应用程序中设置一个规定的索引获取顺序,例如,只能按照主键索引->普通索引的顺序获取锁,这样就可以避免不同的线程出现获取不同顺序锁的情况,进而避免死锁的发生(靠SQL保证)。
60秒标准回答:
因为数据库的锁锁的是索引,并不是记录
当我们在事务中,更新一条记录的时候,如果用到普通索引作为条件,那么会先获取普通索引的锁,然后再尝试获取主键索引的锁
那么这个时候,如果刚好有一个线程,已经拿到了这条记录的主键索引的锁后,同时尝试在该事务中去拿该记录的普通索引的锁
**答题顺序:**结论 → 原理/机制 → 关键流程 → 场景与取舍 → 易错点
回答主线:
- **要点1:**因为数据库的锁锁的是索引,并不是记录。
- **要点2:**当我们在事务中,更新一条记录的时候,如果用到普通索引作为条件,那么会先获取普通索引的锁,然后再尝试获取主键索引的锁。
- **要点3:**那么这个时候,如果刚好有一个线程,已经拿到了这条记录的主键索引的锁后,同时尝试在该事务中去拿该记录的普通索引的锁。
**记忆锚点:**MySQL只操作同一条记录 → 那么会先获取普通索引 → 后再尝试获取主键索引 → 了这条记录的主键索引 → 去拿该记录的普通索引 → 中设置一个规定的索引
易错提醒:
- 为了避免这种死锁情况的发生,可以在应用程序中设置一个规定的索引获取顺序,例如,只能按照主键索引->普通索引的顺序获取锁,这样就可以避免不同的线程出现获取不同顺序锁的情况,进而避免死锁的发生(靠SQL保证)。
加分表达:
- 当我们在事务中,更新一条记录的时候,如果用到普通索引作为条件,那么会先获取普通索引的锁,然后再尝试获取主键索引的锁。
- 那么这个时候,如果刚好有一个线程,已经拿到了这条记录的主键索引的锁后,同时尝试在该事务中去拿该记录的普通索引的锁。
追问准备:
- 围绕「MySQL只操作同一条记录」:底层原理是什么?使用时有哪些边界和常见坑?
- 围绕「那么会先获取普通索引」:底层原理是什么?使用时有哪些边界和常见坑?
- 围绕「后再尝试获取主键索引」:底层原理是什么?使用时有哪些边界和常见坑?
- 如果线上出现异常,你会如何定位、验证并规避?
典型回答
会。
因为数据库的锁锁的是索引,并不是记录。
当我们在事务中,更新一条记录的时候,如果用到普通索引作为条件,那么会先获取普通索引的锁,然后再尝试获取主键索引的锁。
那么这个时候,如果刚好有一个线程,已经拿到了这条记录的主键索引的锁后,同时尝试在该事务中去拿该记录的普通索引的锁。
这时候就会发生死锁。
java
update my_table set name = 'hollis',age = 22 where name = "hollischuang";
这个SQL会先对name加锁, 然后再回表对id加锁。
-----
select * from my_table where id = 15 for update;
update my_table set age = 33 where name like "hollis%";
以上SQL,会先获取主键的锁,然后再获取name的锁。为了避免这种死锁情况的发生,可以在应用程序中设置一个规定的索引获取顺序,例如,只能按照主键索引->普通索引的顺序获取锁,这样就可以避免不同的线程出现获取不同顺序锁的情况,进而避免死锁的发生(靠SQL保证)。