mysql的锁机制
之前主要用kv存储, 没怎么用过mysql. 最近项目上遇到一个问题, 本来以为只是一个简单delete然后insert操作, 都没有用到事务, 实际运行过程中竟然偶发性的会报deadlock错误. 网上找了不少资料, 大概了解了死锁的原理是因为两个insert操作内部有隐性的事务, 然后两个语句一开始各自抢到了S锁, 然后同时等待X锁, 就死锁了. 但是对于这里的具体原理还是不太清晰.
参考文章: https://learnku.com/articles/39212?order_by=vote_count& 通过例子让人比较好理解
https://cloud.tencent.com/developer/article/1181532?from=15425 比较详细
https://cloud.tencent.com/developer/article/1670785
https://keithlan.github.io/2017/06/05/innodb_locks_1/ 各种锁介绍的比较详细
https://blog.csdn.net/qq_40378034/article/details/90904573
总结:
- select .. where name=xxx for update, 其中name是唯一键. 如果能搜到, 那么只加行锁, 如果不存在, 那会加gap锁. gap锁会阻塞意向锁
- mysql中索引分聚簇索引和二级索引, 区别是聚簇索引对应主键索引, b+树的叶子结点包含了数据, 而二级索引的叶子结点只包含了主键ID, 获取数据是需要再走一次聚簇索引. 因此筛选条件使用了二级索引时, 既要对二级索引加锁, 也要对聚簇索引加锁
- 意向锁是表级锁,分为读意向锁和写意向锁。当事务要在一行数据上加上读锁或写锁时,首先要在表上加上意向锁。这样判断表中是否有行锁只要检查表上是否有意向锁。
- 插入意向锁是一种特殊的间隙锁,表示插入的意向,只有在 INSERT 的时候才会有这个锁。间隙锁唯一的作用就是防止其他事务插入记录造成幻读,正是由于在执行 INSERT 语句时需要加插入意向锁,而插入意向锁和间隙锁冲突,从而阻止了插入操作的执行。
- select ENGINE_TRANSACTION_ID, index_name, lock_type, lock_mode, LOCK_STATUS, lock_data from performance_schema.data_locks; 执行这条命令查看加的锁. 注意LOCK_MODE为X表示next-key锁, S,GAP表示间隙锁, X,REC_NOT_GAP才是行记录锁. 还有一个例外:如果在
supremum record
上加锁,locks gap before rec
会省略掉,间隙锁会显示成lock_mode X
“这里想给大家说明的是在innodb日志中如果提示 lock mode S /lock mode X,其实是Next-key lock/Gap lock,如果是行记录锁的话,日志会提示but not gap,请读者朋友们在自己分析死锁日志的时候注意。”