欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MySQL InnoDB update锁表问题Record Locks

程序员文章站 2024-01-13 16:10:10
...

最近做的项目中出现了锁表的问题,导致表无法进行事务(DML)操作,经过排查发现,我们项目中的购物车表有个字段cart_id为uuid类型,并且未设置索引,这里的场景是根据cart_id进行更新内容,Mysql InnoDB行锁不使用索引锁表的时候会锁整张表。

通过命令查询锁日志找到相关锁的sql语句:

show engine innodb status;


mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 485176, OS thread handle 140383913969408, query id 12481371 222.93.77.61 root updating
UPDATE `o_cart_detail` SET MODIFY_TIME = now() WHERE (`cart_id`='1')
------- TRX HAS BEEN WAITING 28 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 2655 page no 4 n bits 144 index PRIMARY of table `o_cart_detail` trx id 5518915 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 15; compact format; info bits 0

通过执行计划分析sql语句:

MySQL InnoDB update锁表问题Record Locks

通过执行计划来看,更新语句并未使用到索引。并且where条件的字段是非索引字段,此时的更新操作是全表锁。

此时我们的修改方案是先进行cart_id字段添加索引,保证业务正常进行。

添加非唯一索引后。再次进行执行计划分析sql语句。此时锁定的记录行从2058 ->  55;此时的更新操作是行锁。

当然最好还是使用唯一索引进行DML操作。

MySQL InnoDB update锁表问题Record Locks

总结:InnoDB 的锁,与索引类型,事务的隔离级别相关。InnoDB 到底是行锁还是表锁取决于你的 SQL 语句。如果查询没有命中索引,也将退化为表锁。InnoDB 的行锁是实现在索引上的,而不是锁在物理行记录上。所以如果访问没有命中索引,也无法使用行锁,将要退化为表锁