这篇文章主要讲的是如何通过调试MySQL源码,知道一条SQL真正会拿哪些锁,不再抓虾,瞎猜或者何登成大神没写过的场景就不知道如何处理了。
通过好多个深夜艰难的单步调试,终于找到了一个理想的断点,可以看到所有的获取锁的过程
具体方式:使用CLion+MySQL官方源码
代码在lock0lock.c
的static enum db_err lock_rec_lock()
函数中,这个函数会显示,获取锁的过程,以及获取锁成功与否的情况
以一个实际的死锁例子来看
死锁日志如下
*** (1) TRANSACTION: |
经过排查代码,是由下面的代码并发执行导致的
INSERT IGNORE INTO xx_dynamic_student_relation (id, dynamic_uid, student_uid, parent_uids, parent_names , state, create_time, update_time, is_deleted, performance_id) VALUES (NULL, '11c62d70d69743118d6f382e43df4bec', 'f91792488255466aa00971fa78306c5f', '["3d08530b61d3465eb9e9e1079c5da773"]', '["凌秋燕"]' , 1, '2018-10-23 21:03:46.193', '2018-10-23 00:00:00.333', 0, NULL) ; |
表结构
CREATE TABLE `xx_dynamic_student_relation` ( |
可以来实验一下唯一索引冲突的情况下,INSERT IGNORE
在大多数情况下会加什么锁(有一些特殊情况,需要特殊讨论)
可以看到mode=2(LOCK_S)
,对uidx_dynamic_student
加了LOCK_S
锁(哈哈,不要信网上的各种猜测文章,实测最靠谱)
那UPDATE xx_dynamic_student_relation
会加哪些锁?
第一步:
第二步:
可以看到,跟网上说的差不多,
对唯一索引uidx_dynamic_student
加X
锁(1027=LOCK_REC_NOT_GAP + LOCK_X),然后对主键索引PRIMARY
加X
锁
现在就非常清楚了
t1 | t2 | 备注 |
---|---|---|
INSERT IGNORE INTO | - | t1成功获得uk的S锁 DB_SUCCESS |
- | INSERT IGNORE INTO | t2成功获得uk的S锁 DB_SUCCESS |
UPDATE | - | t1尝试获得uk的X锁,但没有成功,处于等待状态 DB_LOCK_WAIT |
- | UPDATE | t2尝试获得uk的X锁,发现死锁产生 DB_DEADLOCK |
- | Deadlock | t2释放S锁 |
成功 | - | - |
对于之前何登成大神博客里面的内容(http://hedengcheng.com/?p=771), 可以做实验逐个验证
id主键+RC
结论: 只对主键加X锁
delete from table_1 where id = 10;
加锁过程如下:
字段 | 值 | 备注 |
---|---|---|
mode | 1027 | LOCK_REC_NOT_GAP + LOCK_X |
index | primary |
id唯一索引+RC
结论:对唯一索引加X锁,对主键索引加X锁
delete from t1 where id = 10
加锁过程如下:
序号 | heap_no | 变量值 | 锁状态 |
---|---|---|---|
1 | 7 | uk_id X锁 | DB_SUCCESS_LOCKED_REC |
2 | 5 | PRIMARY X锁 | DB_SUCCESS_LOCKED_REC |
3 | 7 | uk_id X锁 | DB_SUCCESS |
id非唯一索引+RC
结论:对普通索引加X锁,对主键加X锁
delete from table_3 where id = 10
;
加锁过程如下:
index | heap_no | mode | 锁类型 |
---|---|---|---|
idx_id | 7 | 1027 | X |
primary | 3 | 1027 | X |
idx_id | 7 | 1027 | X |
idx_id | 8 | 1027 | X |
primary | 2 | 1027 | X |
idx_id | 8 | 1027 | X |
id无索引+RC
作为练习题,不列举了
备注
锁有关的常量
LOCK_IS 0 |
相关源代码
/*********************************************************************//** |