首页 > 解决方案 > UPDATE 引用更新表中的字段会导致死锁吗?

问题描述

我有一个这样的查询:

UPDATE loginlogs SET rxbytes = rxbytes + ?, txbytes = txbytes + ? WHERE logid = ?

有时,我的数据库会陷入死锁并SELECT * FROM sys.innodb_lock_waits显示如下挂起的锁:

wait_started    wait_age        wait_age_secs   locked_table    locked_index    locked_type     waiting_trx_id  waiting_trx_started     waiting_trx_age waiting_trx_rows_locked waiting_trx_rows_modified       waiting_pid     waiting_query   waiting_lock_id waiting_lock_mode       blocking_trx_id blocking_pid    blocking_query  blocking_lock_id        blocking_lock_mode      blocking_trx_started    blocking_trx_age        blocking_trx_rows_locked        blocking_trx_rows_modified      sql_kill_blocking_query sql_kill_blocking_connection
2020-12-27 07:43:32     00:00:04        4       `db`.`loginlogs`   PRIMARY RECORD  37075679818     2020-12-27 07:43:32     00:00:04        1       0       19194139        UPDATE loginlogs SET  ... HERE logid = 64634225227638257       37075679818:921:15944673:61     X       37075617021     19191704        UPDATE loginlogs SET ... HERE logid = 64634225227638257       37075617021:921:15944673:61     X       2020-12-27 07:43:07     00:00:29        1       0       KILL QUERY 19191704     KILL 19191704

如您所见,两个相同的查询似乎同时运行。第二个正在等待第一个完成。

我认为 MySQL 应该像这样处理简单的 UPDATE 查询。rxbytes我是否需要先选择字节,然后在不引用txbytes新值的情况下进行更新?

顺便说一句,这在从 MariaDB 10.4.2 更新到 10.4.17 后开始发生,因此我也怀疑 MariaDB 错误并打开了错误报告

标签: mariadblockingdeadlock

解决方案


锁等待不是死锁!

我经常看到这种误解。

您所展示的是锁定等待。也就是说,一个事务正在等待另一个事务。每个 UPDATE 都会锁定它检查的行,并且任何并发的 UPDATE 都必须等待第一个 COMMIT 来释放这些行锁。这是一个锁定等待。这是正常和常见的。

僵局是不同的。这是两个事务进入相互锁定等待的地方。UPDATE1 锁定一些行,但尚未提交。然后 UPDATE2 尝试更新相同的行,并开始等待。然后 UPDATE1 的事务尝试另一个锁定语句,该语句需要锁定 UPDATE2 的事务已经持有的某些行,可能来自它运行的先前语句。因此,两个事务都在等待另一个事务,并且不会提交释放它们持有的锁,因为它们正在等待。死锁之所以如此命名,是因为没有办法解决相互等待。

https://dev.mysql.com/doc/refman/8.0/en/innodb-deadlocks.html说:

死锁是一种不同事务无法继续进行的情况,因为每个事务都持有另一个需要的锁。因为两个事务都在等待资源变得可用,所以它们都不会释放它持有的锁。

您不会遇到真正死锁的延迟。MySQL 监视这些循环锁定等待并强制其中一个回滚其事务。这几乎是立即发生的,因此几乎不需要等待。

那么,当您从 MariaDB 10.4.2 升级到 10.4.17 时,为什么会发生这种情况。显然,某些更改会影响锁定的行数或事务的持续时间,以使您更有可能以这种方式发生并发事务冲突。

否则,软件并没有改变任何与锁定或事务相关的内容,但巧合的是,当您升级到新版本的 MariaDB 时,您的流量发生了变化。


推荐阅读