MySQL事务中使用for update查询如何避免造成表锁

时间:2024-04-07 20:32:42

表索引情况

  • id:主键索引
  • name:无索引
  • good_id:无索引
  • user_id:普通索引

当update语句的where条件使用无索引的good_id字段时

事务A更改good_id=1的字段,但提交:

MySQL事务中使用for update查询如何避免造成表锁

事务B更改good_id=2的行,发生锁等待:

MySQL事务中使用for update查询如何避免造成表锁

锁查看:

MySQL事务中使用for update查询如何避免造成表锁

结果:事务2锁等待

 

改用有索引的user_id作为where条件

’事务A:

MySQL事务中使用for update查询如何避免造成表锁

事务B:

MySQL事务中使用for update查询如何避免造成表锁

结果:事务1和事务2都无需等待,瞬间执行

 

结论

MySQL在每个事物中的update操作,都会加X锁,当update语句无where条件,或者where条件无索引时,会锁住整张表,导致并发的其他事务即便修改的不是同一行,仍要等待前面事务结束释放锁。

开发建议

我们在开发中,一般在更改某条记录时,为了避免并发下对同一条数据操作造成数据不一致,会按照如下步骤操作

  1. select ...for update查询,此时在事务结束之前其他事务不能对当前记录进行任何更改操作
  2. 更改某个字段之后再save保存
  3. 提交事务

这个步骤是没问题的,但是为了避免操作同一张表的不同记录引起表锁等待,我们需要在select语句的where条件上建立索引,这样锁住的是更改的那一行数据,不会导致其他不相干的事务等待锁。