【问题标题】:MySql error > Lock wait timeout exceeded; try restarting transaction SQLState: 41000 VendorError: 1205MySql 错误 > 超过锁定等待超时;尝试重新启动事务 SQLState:41000 VendorError:1205
【发布时间】:2013-02-05 08:57:36
【问题描述】:

我多年来一直在处理这个问题,但一直无法深入了解它。我不知道是什么导致了这些锁。

错误是:Lock wait timeout exceeded; try restarting transaction SQLState: 41000 VendorError: 1205

SQL 语句是在事务中运行的单个插入语句。所有插入都是这种形式,因此没有批量插入或混合模式插入等。

INSERT INTO attachment( id, entityid, entitytype , addeduserid , deleteduserid , fullpath , filename, status, creationdate, lastupdated, deletiondate, hasfile,notes,history,type,mimeinfo,archivedby,archivedon, referencedate,changedby,changedon ) values (0,0,2,360,null,NULL,NULL,1,'2013-02-20 08:45:31','2013-02-20 08:45:31',NULL,0,NULL,'20/02/2013 08:45:UserA:File uploaded internally. <br>',0,NULL,null,NULL,NULL,null,NULL);

系统配置: Mysql version: 'Server version: 5.1.61 Source distribution' (on Redhat)

存储:INNODB

INNODB相关配置(部分来自my.cnf):

innodb_file_per_table=1
innodb_buffer_pool_size=3G
innodb_additional_mem_pool_size=20M
innodb_log_file_size=512M
innodb_log_files_in_group=2
innodb_log_buffer_size=16M
innodb_support_xa=1
innodb_doublewrite=1
innodb_thread_concurrency=0
innodb_flush_log_at_trx_commit=2
innodb_autoinc_lock_mode=2**
innodb_rollback_on_timeout=1
innodb_locks_unsafe_for_binlog=1**
thread_cache_size=8
query_cache_size=256M
query_cache_limit=4M
table_cache=2048
table_definition_cache=1024
tmp_table_size=512M
max_heap_table_size=512M
transaction-isolation=READ-COMMITTED**
innodb_table_locks=0**
innodb_lock_wait_timeout=50**

** 这些是专门针对此问题添加的。

一般:

系统(即有 6 个应用程序实例,每个实例都具有相同的数据库结构,都在一个 mysql 实例上运行)可以运行好几天,然后可以在开始发生锁定等待的情况下运行,并且通常会使它们以组的形式出现在一天的时间里。每个单独的错误都会重复发生,因为一旦失败,我会再试一次,通常重试会失败。我已配置为重试 4 次。通常,锁只会出现在几个不同的表上。

今天问题的具体实例:

今天早上在attachment 表上,自昨晚以来,表上没有插入。自前一天晚上以来,桌面上也没有任何更新。 如果锁与其他用户进行更新和插入无关,那么某些选择语句会导致锁吗?我试图确保所有选择语句都使用attachment_general_index?

由于我主要在几个不同的表上得到这个 - 这是这个表的结构。

CREATE TABLE `attachment` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`entityid` int(10) unsigned DEFAULT NULL,
`entitytype` tinyint(3) unsigned NOT NULL DEFAULT '0',
`addeduserid` int(10) unsigned NOT NULL,
`deleteduserid` int(10) unsigned DEFAULT NULL,
`fullpath` varchar(255) DEFAULT NULL,
`filename` varchar(255) DEFAULT NULL,
`status` tinyint(3) unsigned NOT NULL DEFAULT '0',
`creationdate` varchar(40) DEFAULT NULL,
`lastupdated` varchar(40) DEFAULT NULL,
`deletiondate` varchar(40) DEFAULT NULL,
`hasfile` tinyint(3) unsigned NOT NULL DEFAULT '0',
`notes` text,
`history` text,
`type` tinyint(3) unsigned DEFAULT '0',
`lastupdatedby` int(10) DEFAULT '0',
`lastupdatedinfo` varchar(255) DEFAULT NULL,
`mimeinfo` varchar(255) DEFAULT NULL,
`archivedby` int(10) unsigned DEFAULT NULL,
`archivedon` varchar(40) DEFAULT NULL,
`referencedate` varchar(40) DEFAULT NULL,
`changedby` int(10) unsigned DEFAULT NULL,
`changedon` varchar(40) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `attachment_addeduserid_fkey` (`addeduserid`),
KEY `attachment_deleteduserid_fkey` (`deleteduserid`),
KEY `attachment_archivedby_fkey` (`archivedby`),
KEY `attachment_changedby_fkey` (`changedby`),
KEY `attachment_general_index` (`entitytype`,`entityid`,`status`,`type`),
CONSTRAINT `attachment_ibfk_1` FOREIGN KEY (`addeduserid`) REFERENCES `user` (`id`),
CONSTRAINT `attachment_ibfk_2` FOREIGN KEY (`deleteduserid`) REFERENCES `user` (`id`),
CONSTRAINT `attachment_ibfk_3` FOREIGN KEY (`archivedby`) REFERENCES `user` (`id`),
CONSTRAINT `attachment_ibfk_4` FOREIGN KEY (`changedby`) REFERENCES `user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3619 DEFAULT CHARSET=latin1$$

我附上了最近的 SHOW INNODB STATUS,这是从今天开始的,从昨天开始就没有锁等待。我不明白所有这些输出,但主要是锁似乎从未出现在这里。我认为是因为它们没有被归类为死锁?

https://docs.google.com/document/d/1Hslf2B594n8ofAUYxN54Gh8FrSCIFNGGMtthVI_Lv4k/pub

是否只有死锁区域对此问题感兴趣?如果有其他方面我会尽量收集,当它发生并可以提供。

任何帮助将不胜感激。

尼克

【问题讨论】:

  • SHOW INNODB STATUS 说什么?
  • 另外,交易中还有什么错误的?我猜至少还有一个插入,因为这很容易导致:xaprb.com/blog/2006/08/03/…
  • @Danack ,请参阅上面的链接到 SHOW INNODB STATUS 的一些输出。对于失败的事务,一般不会有大量的动作,但一般不会在同一个事务中两次插入到同一个表中。关于 xaprb 链接(我很久以前读过) - 但由于情况的性质,我认为它不适用?感谢您的关注!
  • 另一个想法。您应该打开慢查询日志,并尝试将 ER_LOCK_WAIT_TIMEOUT 错误与同时发生的慢查询匹配。如果原因实际上不是事务死锁,而只是一个不在事务中但仍然锁定某物的慢查询,这可能会有所帮助。
  • 我刚刚在使用 START TRANSACTION 并进行大量插入时遇到了这个问题。在某些时候,lock_timeout 启动了,它会在 COMMITTING 时抛出错误。

标签: mysql locking


【解决方案1】:

我想与那些为事务超时而摸不着头脑并发现建议的服务器配置更改都无济于事的人分享我的“尤里卡”时刻。

我陷入了困境,以至于我正在认真考虑重写我的一些应用程序,以便我能够适应事务超时(全世界都听到了集体的呻吟声)。

我对从我的业务交易中丢失任何东西感到偏执,所以我运行一个 cron 作业,全天每 10 分钟执行一次完整的 mysqldump(这是在双重复制之上)。

我发现 mysqldump 占用了服务器,锁定了表,并且几乎禁止其他任何东西在它正在做的事情时使用数据库。当我发现事务失败与 mysqldump 运行时间同时发生时,我的尤里卡时刻到来了。

长话短说,有 3 个命令行选项可以防止 mysqldump 杀死您的服务器。这些是

  1. --单笔交易
  2. --快
  3. --lock-tables=false

非常感谢 CA3LE @How can I slow down a MySQL dump as to not affect current load on the server? 对我的启发。

【讨论】:

    【解决方案2】:

    (这应该是评论,但我的文字太多,需要格式化)。

    我认为这与described at 的问题非常相似,其中:

    1. 一个事务在表的末尾有一个锁。
    2. 第二个事务锁定了大部分表。
    3. 第一个事务尝试更新/插入第二个事务持有的锁。这失败了,因此其中一项交易被选择终止。

    感谢您发布show status。没错,显示的死锁似乎与您所询问的表无关,但它似乎与 Xaprb 中的死锁相同。

    是否只有死锁区域对此问题感兴趣?

    是的,确切的部分是:

    Transaction 1
    
    UPDATE operative SET  lastupdated='2013-02-19 17:12:44'=N<EDITED> RECORD LOCKS space id 1789 page no 3622 n bits 112  index `PRIMARY` of table `<EDITED> `.`operative` trx id 0 233901602  lock_mode X locks rec but not gap waiting
    
    *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 1789 page no 3622 n bits 112 index `PRIMARY` of table `<EDITED> `.`operative`  trx id 0 233901602 lock_mode X locks rec but not gap waiting
    
    
    Transaction 2
    
    INSERT INTO opdate(operativeId,opdate,updatingUser,dategroup,type,notes,lastupdated) values (....) RECORD LOCKS space id 1789 page no 3622 n bits 112 index `PRIMARY` of table `<EDITED> `.`operative`  trx id 0 233901603 lock mode S locks rec but not gap
    
    
    *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 830 page no 112 n bits 808  index `opdate_unique` of table `<EDITED> `.`opdate` trx id 0 233901603 lock mode S waiting Record lock, heap no 739 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
    

    这感觉与 xaprb 中列出的问题非常相似。即

    1. 事务 2 已对表进行了插入操作,现在持有主键上的锁。
    2. 事务 1 正在执行表扫描以进行更新,并且正在等待对该主键的锁定。
    3. 事务 2 正在尝试进行另一次插入,并且需要获取锁,但由于事务 1 已经拥有它而无法执行此操作(实际上我是在猜测那里,因为您混淆了表名)。

    我建议先解决这个死锁,然后尝试解决您所询问的问题。

    其实我觉得你的问题可能不会出现在INNODB状态。您收到错误代码 1205 - 这是 ER_LOCK_WAIT_TIMEOUT,而不是错误 1213 ER_LOCK_DEADLOCK。因此,尽管您实际上遇到了死锁,但它并没有被归为此类。

    我认为,如果您可以在问题发生时执行SHOW ENGINE INNODB STATUS,您应该能够看到那里的停顿事务的锁,即使它们没有显示为最新的死锁。

    【讨论】:

    • 因为我经常会在 50 秒超时后得到重复的锁等待,所以当它发生时我应该能够得到一个副本。但例如我今天没有 - 所以会密切关注。与 xaprb 相比的主要区别在于没有任何其他数据更新的记录(即基于插入和更新时间戳),因此这个带有锁等待的事务是唯一更新表的事务。如果有任何更新完成,它总是使用主键(即它们是单行更新)。因此,表上唯一可能的其他操作是查询。再次感谢
    • @sehe 您的编辑使得在没有水平滚动的情况下无法阅读所有文本。这是你的意图吗?
    • @Danack 不直接。我进行了编辑,因为以前的情况确实无法识别日志中的“节”。原始换行符如何丢失对我来说是一个谜。如果您不介意,我可以尝试用类似但损坏程度较低的东西替换它。
    • 去吧。我习惯于在很小的 ssh 窗口中解析原始 sql 日志,但我可以看到其他人会觉得这很烦人。
    猜你喜欢
    • 2015-09-27
    • 2019-06-02
    • 2021-01-12
    • 2015-02-18
    • 2018-01-12
    • 2016-08-01
    • 2021-08-07
    • 1970-01-01
    • 2018-04-17
    相关资源
    最近更新 更多