MySQL幻读深度剖析:记录锁+间隙锁能阻止删除引发的幻读吗?
面试高频真题MySQL可重复读级别下记录锁间隙锁是否可以防止删除操作带来的幻读本文基于 MySQL8.0 InnoDB结合实验、加锁原理、线上踩坑点把这个问题讲透。一、什么是幻读先看MySQL官方文档对幻读Phantom Read的定义同一个事务内同一条查询SQL在不同时间点执行返回的结果集不一样。比如第二次查询出现了第一次没有的行这一行就被称之为“幻象行”。幻读不只有「多出记录」这一种表现结果集记录变少同样属于幻读。举个简单例子事务先后两次执行相同SQLSELECT * FROM t_test WHERE id 100;T1时刻查询返回5条T2时刻返回6条新增了数据发生幻读T1时刻查询返回5条T2时刻返回4条数据被别的事务删除同样发生幻读。很多同学只记住“新增产生幻读”忽略了其他事务删除数据也会造成幻读现象这也是面试官经常挖坑的地方。InnoDB 可重复读如何处理幻读InnoDB 默认隔离级别是可重复读RR分两种读模式两套不同方案解决幻读快照读普通 select不加锁依靠MVCC多版本并发控制。事务全程读取事务启动时刻的数据快照其他事务新增、删除的数据对当前事务不可见规避幻读。当前读select ... for update/lock in share mode/ update / delete依靠临键锁Next‑Key Lock 记录锁间隙锁。通过锁住索引区间阻塞其他事务的插入、删除、修改操作从物理层面防止幻读。注意快照读与当前读要区分开MVCC只服务快照读只要是加锁的当前读幻读防护完全依靠行锁体系。二、实验验证锁可以防止删除导致的幻读实验环境MySQL8.0隔离级别 RR可重复读 测试表t_user主键索引id测试若干条业务数据。场景复现事务A当前读加锁查询begin; select * from t_user where age 20 for update;事务A查询出所有age大于20的记录一共6条。此时这条SQL属于当前读会对扫描到的索引加临键锁。事务B尝试删除其中一条命中记录begin; delete from t_user where id 2;现象事务B的delete直接阻塞无法执行成功。结论事务A的临键锁阻止了其他事务删除查询范围内的数据也就避免了“别的事务删数据导致A后续查询结果集变少”的幻读问题。三、深度加锁分析锁到底加在了哪里使用MySQL内置视图查看事务持有的锁select * from performance_schema.data_locks\G;重点字段说明LOCK_TYPERECORD代表行级锁不是“记录锁”LOCK_MODEX临键锁 Next‑Key LockLOCK_MODEX, REC_NOT_GAP纯记录锁 Record LockLOCK_MODEX, GAP纯间隙锁 Gap LockLOCK_DATA锁区间的右边界值左边界取该条记录的上一条索引记录。坑点查询条件不走索引直接锁全表上面实验中如果age没有建立索引select ... for update会触发全索引扫描。⚠️重要规则InnoDB的锁是扫描索引的时候逐行加锁不是只给最终返回结果集加锁。没有索引会遍历整张表全部主键索引给每一条索引都加上X临键锁。 上面案例事务A实际给主键索引施加了这些锁(-∞,1]、(1,2]、(2,3]、(3,4]、(4,5]、(5,6]、(6,7]、(7,8]、(8,9]、(9,∞]等于整张表被行锁锁住所有其他事务的增删改全部阻塞数据库并发直接报废。这是生产环境重大故障来源。此时事务B想删除id2被阻塞就很好理解整个表都被锁住。优化给查询字段age建立索引给age创建普通索引index_age再次执行相同的加锁查询。create index index_age on t_user(age); begin; select * from t_user where age 20 for update;现在SQL走二级索引不再全表扫描锁范围大幅缩小。 InnoDB会同时操作两套索引二级索引age上加一组临键锁锁区间化简为(19, ∞]锁住所有age19的索引区间主键索引上对每一条匹配到的记录施加X记录锁。此时其他事务不能向age19区间插入新记录其他事务不能删除/修改命中的主键记录age≤19的数据不受锁影响可以正常增删改。只有扫描到的索引才会加锁走索引可以极大缩小锁粒度提升并发。四、核心总结 线上开发避坑RR级别下当前读通过临键锁记录锁间隙锁既可以阻止插入带来的幻读同样可以阻止删除操作带来的幻读。幻读的本质是同一查询结果集前后不一致不管记录变多还是变少都属于幻读。锁是扫描索引时加锁不是针对返回结果集加锁如果update / delete / select ... for update没有走索引发生全表扫描会给全部索引加临键锁等价锁全表业务直接卡死。区分两套幻读解决方案快照读普通selectMVCC多版本快照当前读加锁/修改SQLNext‑Key Lock临键锁。生产环境规范所有update、delete、for update业务SQL必须用explain确认已经命中索引尽量缩小where条件范围减少锁扫描行数保持事务简短锁随事务提交释放长事务会拉长锁持有时间极易产生锁等待、死锁。面试小tips面试官问幻读不要只讲插入幻读主动补充“删除也会产生幻读依靠记录锁保护已有记录不被别的事务删除”会是加分项。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →