草庐IT

mysql - 解释莫名其妙的死锁

coder 2023-06-11 原文

首先,我完全看不出我怎么会出现任何死锁,因为我没有使用显式锁定,只涉及一个表,每个表都有一个单独的进程要插入、选择和更新行,一次只插入或更新一行,并且每个进程很少(可能一分钟一次)运行。

这是一个电子邮件队列:

CREATE TABLE `emails_queue` (
  `id` varchar(40) NOT NULL,
  `email_address` varchar(128) DEFAULT NULL,
  `body` text,
  `status_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `status` enum('pending','inprocess','sent','discarded','failed') DEFAULT NULL,
  KEY `status` (`status`),
  KEY `status_time` (`status`,`status_time`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

生成过程响应某些用户操作,但大约每 90 秒一次,对表执行一次插入,将状态设置为“待处理”。

有一个监控过程,每分钟检查一次“待处理”和“失败”电子邮件的数量是否过多。运行时间不到一秒钟,而且从未给我带来任何麻烦。

发送进程每分钟都会抓取所有待处理的电子邮件。它循环遍历一次一封电子邮件,将其状态设置为“处理中”,尝试发送它,最后将其状态相应地设置为“已发送”、“已丢弃”(它有理由决定一封电子邮件不应该发出),或“失败”(被 SMTP 系统拒绝)。

设置状态的语句不正常。

UPDATE emails_queue SET status=?, status_time=NOW() WHERE id=? AND status = ?

也就是说,只有当当前状态已经达到我认为的状态时,我才会更新状态。在这个机制之前,我不小心启动了两个发送进程,它们都会尝试发送相同的电子邮件。现在,如果发生这种情况,一个进程会成功地将电子邮件从“待处理”移动到“处理中”,但第二个进程会更新零行,意识到存在问题,然后跳过该电子邮件。

问题是,大约有 100 次更新完全失败!我得到 com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock;尝试重启事务

什么?

这是唯一发生这种情况的表和唯一查询,并且它只发生在生产中(以最大限度地增加调查难度)。

只有两件事看起来很不寻常:(1) 更新参与 WHERE 子句的列,以及 (2) status_time 的(未使用的)自动更新。

我正在寻找任何建议或诊断技术。

最佳答案

首先,死锁不依赖于显式锁定。 MySQL 的 LOCK TABLE 或使用非默认事务隔离模式不需要有死锁。如果您从不使用显式事务,您仍然会遇到死锁。

死锁很容易发生在单个表上。最常见的是来自单个热表。

如果您的所有事务都只执行单行插入,则甚至可能会发生死锁。

如果你有,可能会发生死锁

  • 不止一个数据库连接(显然)
  • 内部涉及多个锁的任何操作。

不明显的是,大多数时候,单行插入或更新涉及多个锁。这样做的原因是二级索引在插入/更新期间也需要锁定。

SELECT 不会锁定(假设您使用的是默认隔离模式,并且没有使用 FOR UPDATE)所以它们不可能是原因。

SHOW ENGINE INNODB STATUS 是你的 friend 。它会给你一堆(诚然非常困惑)关于死锁的信息,特别是最近的。

  • 您无法完全消除死锁,它们将继续在生产中发生(即使在测试系统上,如果对它们施加适当的压力)
  • 以尽可能少的死锁为目标。如果 1% 的交易死锁,那可能太多了。
  • 如果您完全理解其中的含义,请考虑将事务的事务隔离级别更改为已提交读
  • 确保您的软件能够正确处理死锁。

关于mysql - 解释莫名其妙的死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5970210/

有关mysql - 解释莫名其妙的死锁的更多相关文章

  1. ruby - 有人可以帮助解释类创建的 post_initialize 回调吗 (Sandi Metz) - 2

    我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法

  2. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  3. ruby - 解释为局部变量会覆盖方法名称吗? - 2

    如thisquestion,当在其自己的赋值中使用未定义的局部变量时,它的计算结果为nil。x=x#=>nil但是当局部变量的名称与现有的方法名称冲突时,就比较棘手了。为什么下面的最后一个示例返回nil?{}.instance_eval{a=keys}#=>[]{}.instance_eval{keys=self.keys}#=>[]{}.instance_eval{keys=keys}#=>nil 最佳答案 在Ruby中,因为可以在没有显式接收器和括号的情况下调用方法,所以在局部变量引用和无接收器无参数方法调用之间存在语法歧义:f

  4. 语法类似于 GitHub Flavored Markdown 的 Ruby markdown 解释器? - 2

    我使用Jekyll运行博客,并认为我会解决RedcarpetMarkdown解释器,因为它是developedandusedbyGitHub.好吧,我只是碰巧遇到了一个错误,去检查问题,然后foundthis.Maintainersays,"Asyouprobablyhavenoticed(harharharhar)Idon'thavetimetomaintainRedcarpetanymore.It'snotapriorityforme(IfindMarkdownthoroughlyboring)andit'snotapriorityforGitHub,becausewenolong

  5. ruby-on-rails - 无法安装 mysql2 0.3.14 gem - 2

    我看到其他人也遇到过类似的问题,但没有一个解决方案对我有用。0.3.14gem与其他gem文件一起存在。我已经完全按照此处指示完成了所有操作:https://github.com/brianmario/mysql2.我仍然得到以下信息。我不知道为什么安装程序指示它找不到include目录,因为我已经检查过它存在。thread.h文件存在,但不在ruby​​目录中。相反,它在这里:C:\RailsInstaller\DevKit\lib\perl5\5.8\msys\CORE\我正在运行Windows7并尝试在Aptana3中构建我的Rails项目。我的Ruby是1.9.3。$gemin

  6. ruby - 如何使用 ruby​​ mysql2 执行事务 - 2

    我已经开始使用mysql2gem。我试图弄清楚一些基本的事情——其中之一是如何明确地执行事务(对于批处理操作,比如多个INSERT/UPDATE查询)。在旧的ruby-mysql中,这是我的方法:client=Mysql.real_connect(...)inserts=["INSERTINTO...","UPDATE..WHEREid=..",#etc]client.autocommit(false)inserts.eachdo|ins|beginclient.query(ins)rescue#handleerrorsorabortentirelyendendclient.commi

  7. ruby - 有人可以解释一下在 Ruby 中注入(inject)的真实、通俗易懂的用法吗? - 2

    我正在学习Ruby,遇到了inject。我正处于理解它的风口浪尖,但当我是那种需要真实世界的例子来学习一些东西的人时。我遇到的最常见的例子是人们使用inject来添加一个(1..10)范围的总和,我不太关心这个。这是一个任意的例子。在实际程序中我会用它做什么?我正在学习,所以我可以继续使用Rails,但我不必有一个以Web为中心的示例。我只需要一些我可以全神贯注的目标。谢谢大家。 最佳答案 inject有时可以通过它的“其他”名称reduce更好地理解。它是一个对Enumerable进行操作(迭代一次)并返回单个值的函数。它有许多有

  8. ruby - 一种语言如何被自身解释(如 Rubinius)? - 2

    我使用Ruby编程已经有一段时间了,现在只使用Ruby的标准MRI实现,但我一直对我经常听到的其他实现感到好奇。前几天我在读有关Rubinius的文章,这是一个用Ruby编写的Ruby解释器。我试着在不同的地方查找它,但我很难弄清楚这样的东西到底是如何工作的。我在编译器或语言编写方面从来没有太多经验,但我真的很想弄明白。一门语言究竟如何才能被自己解释?编译中是否有一个我不明白这有意义的基本步骤?有人可以像我是个白痴一样向我解释这个吗(因为无论如何这都不会太离谱) 最佳答案 它比你想象的要简单。Rubinius并非100%用Ruby编

  9. ruby-on-rails - 当我通过 rvm 使用 rails3 时,如何在 ubuntu 上安装 mysql2 gem? - 2

    我正在尝试绕过rails配置这个极其复杂的迷宫。到目前为止,我设法在ubuntu上设置了rvm(出于某种原因,ruby在ubuntu存储库中已经过时了)。我设法建立了一个Rails项目。我希望我的测试项目使用mysql而不是mysqlite。当我尝试“rakedb:migrate”时,出现错误:“!!!缺少mysql2gem。将其添加到您的Gemfile:gem'mysql2'”当我尝试“geminstallmysql”时,出现错误,告诉我需要为安装命令提供参数。但是,参数列表很大,我不知道该选择哪些。如何通过在ubuntu上运行的rvm和mysql获取rails3?谢谢。

  10. Ruby 代码解释 - 2

    谁能解释一下这段Ruby代码:defadd_spec_path_to(args)#:nodoc:args我看到了运算符用于连接字符串或在其他语言中用作按位运算符,但有人可以在这种情况下对其进行解释。它是以某种方式将一个空白的lamda附加到args上还是我完全错了?我还可以看到它是这样使用的:before_parts(*args)是Hash关键字?我也不确定||=是什么接线员在说。我同样对什么一无所知caller(0)[2]是。 最佳答案 我假设args是一个Array。Hash是类的名称-第一行将空哈希{}推送到argsunles

随机推荐