首先来看一个next-key lock的例子 Set autoCommit = 0; update furniture_oms__shipping_plan_line_b_o set buyerName = '231' where shippingPlan = 18 这时候的锁定范围为 shippingPlan >16 锁定范围 <19 id >12 锁定范围 < 18 没错id也会属于锁定范围 这时候我们执行 update furniture_oms__shipping_plan_line_b_o set buyerName = '231' where id = 15 这条语句不会被锁定 因为shippingPlan 和 id是两个不同的索引 所以互不影响 但是我们执行 insert into furniture_oms__shipping_plan_line_b_o values(16, 100,’ dadadad’ ) 这时候会锁定 等待 上面的提交 或者执行 update furniture_oms__shipping_plan_line_b_o set id = 13 where shippingPlan = 24 或者执行 update furniture_oms__shipping_plan_line_b_o set id = 13 where orderStatus = ‘wanqianhaoXiao' 或者执行 update furniture_oms__shipping_plan_line_b_o set shippingPlan = 17 where orderStatus = ‘wanqianhaoXiao' 这几条语句都会锁定 其实可以看一下 当我们要更新某个字段的时候 也会判断这个字段对应的锁 是否在被锁定中 如果被锁定中 就不会更新 虽然他们的where条件各不相同 比如上面的语句 我们要将id更新为13 但是 12-18范围内的id都已经被锁定了 所以不允许更新 我们要将shippingPlan更新为17 但是16-19范围内的shippingPlan都已经被锁定了 所以也不允许更新。 其实如果你把mysql的隔离级别降为读已提交 你会发现下面的绝大多数的语句都能执行。 为什么 读已提交不行 我列举一个场景 我们知道读已提交的隔离级别 binlog同步的是sql语句 看一下下面的情况 Transactional1 transactional2 Set autoCommit = 0 Set autoCommit = 0 Update table name = “dada” where shippingPlan = 13 Update table shippingPlan = 13 where id = 10000 Commit; Commit; 这时候主从同步的时候 从服务器 回放这两条sql语句的时候 因为是事物2先提交到 所以事物2先到 这时候 执行就会造成数据不一致。 总结 mysql的next-key lock 是锁定的一个范围和当前行 任何一个索引都会根据自己的索引锁定一个范围和id的一个范围。 索引之间是不冲突的 只要你不是都是更新同一行。 当你要吧某个值进行set的时候 也会判断你要set之后的值 是否已经被别的事物给锁定了 这时候不允许更新。 所以我们可以大胆的说一句 在很多场景下 间隙锁影响的是Insert 因为你不会经常更新索引字段吧。



