InnoDB 是使用行级锁定。
问题是,应用程序或 ORM 以错误的方式使用它,没有为 MySQL 提供足够的信息来说明要做什么,从而导致死锁。
最简单的 - 我赶紧说,不是最有效的! - 如果您发现更新都发生在同一小组方法中,则解决此问题的方法可能是诉诸建议锁定。
请注意,您的死锁在该表中是完全不给定的;您应该运行 SHOW ENGINE INNODB STATUS 以查看最后检测到的死锁是什么。例如,您会发现:
LATEST DETECTED DEADLOCK
------------------------
200915 11:31:03
*** (1) TRANSACTION:
TRANSACTION 22B8A76B9, ACTIVE 0 sec starting index read
mysql tables in use 3, locked 3
LOCK WAIT 4 lock struct(s), heap size 1248, 4 row lock(s)
MySQL thread id 11161737, OS thread handle 0x7fd06d708700, query id ... UPDATE table SET ... WHERE Dat_UsrId = '11254' && Dat_CreUte='...' && Dat_Tip = 'C'
*** (2) TRANSACTION:
TRANSACTION 22B8A76B4, ACTIVE 0 sec fetching rows
mysql tables in use 3, locked 3
2616 lock struct(s), heap size 244152, 7262 row lock(s)
MySQL thread id 11161676, OS thread handle 0x7fd06ca97700, query id ... UPDATE table SET ... WHERE ...
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 866959 page no 46 n bits 1616 index `NewIndex2` of table `schema`.`table` trx id 22B8A76B4 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 866959 page no 68831 n bits 72 index `PRIMARY` of table `schema`.`table` trx id 22B8A76B4 lock_mode X locks rec but not gap waiting
Record lock, heap no 5 PHYSICAL RECORD: n_fields 18; compact format; info bits 0
*** WE ROLL BACK TRANSACTION (1)
------------
请注意,这里的逻辑错误出现在事务 2 的查询中。这是一个非常强烈的提示:
2616 lock struct(s), heap size 244152, 7262 row lock(s)
...WHERE 需要锁定 7262 行 (!),从应用程序逻辑的角度来看,这完全是荒谬的(另请参阅 this 了解“间隙”的解释)。
否则,您可以借助LOCK TABLE form_responses WRITE 使用显式事务和表级锁定。
最有效的方法是让所有涉及的方法进入显式事务:
SET autocommit = 0;
UPDATE form_responses ... WHERE id = ...;
COMMIT WORK;