MySQL 5.6死锁,用于两次锁定同一行



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

从下面的代码片段中,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,已锁定1LOCK WAIT 31锁结构,堆大小6960,6行锁MySQL线程id 2944,操作系统线程句柄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 space id 128954第5页n位176表"db_test1"的索引"PRIMARY"`table_meta`trx id 2333130 lock_mode X锁定rec但不锁定间隙等待***(2)交易:TRANSACTION 2333255,ACTIVE 0秒启动索引读取mysql表在用1,已锁定13个锁结构,堆大小1248,11个行锁MySQL线程id 2927,操作系统线程句柄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)FOR UPDATE***(2)持有锁:RECORD LOCKS space id 128954第5页n位176表"db_test1"的索引"PRIMARY"`table_meta`trx id 2333255 lock_mode X锁定rec但不锁定gap***(2)等待该锁定被授予:RECORD LOCKS space id 128954第5页n位176表"db_test1"的索引"PRIMARY"`table_meta`trx id 2333255 lock_mode X锁定rec但不锁定间隙等待***我们回滚交易(2)

当然,

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

你有从属服务器吗?

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

简单的方法;

  1. 试着找出死锁案例中涉及的表
  2. 确定哪个表在INSERT/UPDATE/DELETE方面应该优先于其他表
  3. 只需使用LOCK TABLES包装相关查询。。。UNLOCK TABLES语句(如果存在,则应使用别名)

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

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

最新更新