MySQL 5.6 死锁两次锁定相同的行?

Posted

技术标签:

【中文标题】MySQL 5.6 死锁两次锁定相同的行?【英文标题】:MySQL 5.6 deadlock for locking the same rows twice? 【发布时间】:2013-07-27 08:42:26 【问题描述】:

我看到 mysql 5.6 出现死锁,因为似乎试图锁定同一行两次。

从下面的 sn-p 中,id = (11, 12, 13, 14, 15) 的行已经有了锁。当另一个事务试图获取这些锁时,MySQL 检测到死锁的事务失败。

我对此的理解正确吗?如果是这样,MySQL 5.6 中有什么可以解决这个问题吗? FWIW,5.5 中的相同代码运行良好(数百次迭代)。

---------------------- 最新检测到的死锁 ---------------------- 2013-07-25 11:46:05 13a515000 *** (1) 交易: TRANSACTION 2333130,ACTIVE 0 秒获取行 mysql 表正在使用 1,锁定 1 LOCK WAIT 31 个锁结构,堆大小 6960,6 行锁 MySQL 线程 id 2944,OS 线程句柄 0x13ae88000,查询 id 184533 localhost 127.0.0.1 root 发送数据 SELECT id FROM table_meta WHERE id IN (11, 12, 13, 14, 15) FOR UPDATE *** (1) 等待授予此锁定: RECORD LOCKS 空间 id 128954 页号 5 n 位 176 表 `db_test1`.`table_meta` 的索引 `PRIMARY` trx id 2333130 lock_mode X 锁定记录但不锁定间隙等待 *** (2) 交易: TRANSACTION 2333255,ACTIVE 0 秒开始索引读取 mysql 表正在使用 1,锁定 1 3 个锁结构,堆大小 1248,11 行锁 MySQL 线程 id 2927,OS 线程句柄 0x13a515000,查询 id 186769 localhost 127.0.0.1 root 发送数据 SELECT id FROM table_meta WHERE id IN (1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 15) 进行更新 *** (2) 持有锁: 记录锁空间 id 128954 页号 5 n 位 176 表 `db_test1`.`table_meta` 的索引 `PRIMARY` trx id 2333255 lock_mode X 锁定记录但不锁定间隙 *** (2) 等待授予此锁定: RECORD LOCKS 空间 id 128954 页号 5 n 位 176 表 `db_test1`.`table_meta` 的索引 `PRIMARY` trx id 2333255 lock_mode X 锁定记录但不锁定间隙等待 *** 我们回滚交易 (2)

【问题讨论】:

即使我也看到了相同的......急切地寻找更新...... 【参考方案1】:

我们需要更好地了解整个交易 (尤其是从 1 到 15 的一个锁定行)给你一个具体的答案。 好像你有这个事务锁定表一次,然后在同一个事务中再次锁定它。 您必须在同一事务的两个 SELECT FOR UPDATE 之间提交。

【讨论】:

【参考方案2】:

简单的方法;

    尝试找出死锁情况涉及的表; 确定在 INSERT/UPDATE/DELETE 方面哪个表应优先于其他表; 只需使用 LOCK TABLES...UNLOCK TABLES 语句包装相关查询(如果存在,则应使用别名)

希望不是所有的语句/表格都需要这个总结,只有关键的一个。

【讨论】:

【参考方案3】:

当然,

刚刚在 5.6 中为我的一位客户排序。实际上这些是 innodb 死锁,select 后面跟着一个导致死锁的更新。请更新查询并进行单独更新。

你有从服务器吗?

还有一点需要注意——INSERT ... SELECT 还在锁定模式下执行读取,因此部分绕过版本控制并检索最新提交的行。所以即使你在 REPEATABLE-READ 模式下操作,这个操作也会在 READ-COMMITTED 中执行 模式,与纯 SELECT 给出的结果相比,可能会给出不同的结果。顺便说一句,这也适用于 SELECT .. LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE 。 我的一个问题是,如果我不使用复制并且禁用了我的二进制日志会怎样?如果不使用复制,您可以启用 innodb_locks_unsafe_for_binlog 选项,这将放松 Innodb 在语句执行时设置的锁,这通常会提供更好的并发性。但是,顾名思义,它会使锁在前复制和时间点恢复中变得不安全,因此请谨慎使用 innodb_locks_unsafe_for_binlog 选项。

【讨论】:

以上是关于MySQL 5.6 死锁两次锁定相同的行?的主要内容,如果未能解决你的问题,请参考以下文章

PHP MySQL 相同的查询返回不同的行数

当在 2 个连续的行中调用两次时,Faker 正在生成重复数据(Typescript)

第9章 线程编程_死锁

MySQL 从一张表查询 - 选择相同的字段两次

在mysql中以不同月份显示相同数据(或值)两次的查询

从锁定屏幕启动时,Android Activity 会打开两次