为了账号安全,请及时绑定邮箱和手机立即绑定

如何避免mysql'试图锁定时发现死锁; 尝试重启事务'

如何避免mysql'试图锁定时发现死锁; 尝试重启事务'

慕斯王 2019-08-06 13:54:44
如何避免mysql'试图锁定时发现死锁; 尝试重启事务'我有一个innoDB表记录在线用户。它会在用户每次刷新页面时更新,以跟踪他们所在的页面以及他们上次访问网站的日期。然后,我有一个每15分钟运行一次以删除旧记录的cron。我得到了一个'试图锁定时发现的死锁; 尝试重新启动事务'昨晚约5分钟,似乎是在这个表中运行INSERT。有人可以建议如何避免这个错误?===编辑===以下是正在运行的查询:首次访问网站:INSERT INTO onlineusers SETip = 123.456.789.123,datetime = now(),userid = 321,page = '/thispage',area = 'thisarea',type = 3在每个页面刷新:UPDATE onlineusers SETips = 123.456.789.123,datetime = now(),userid = 321,page = '/thispage',area = 'thisarea',type = 3WHERE id = 888Cron每15分钟一次:DELETE FROM onlineusers WHERE datetime <= now() - INTERVAL 900 SECOND然后它会记录一些统计数据(即:在线成员,在线访客)。
查看完整描述

3 回答

?
四季花海

TA贡献1811条经验 获得超5个赞

可以帮助解决大多数死锁的一个简单技巧是按特定顺序对操作进行排序。

当两个事务试图以相反的顺序锁定两个锁时,你会遇到死锁,即:

  • 连接1:锁定键(1),锁定键(2);

  • 连接2:锁定键(2),锁定键(1);

如果两者同时运行,则连接1将锁定密钥(1),连接2将锁定密钥(2),并且每个连接将等待另一个连接释放密钥 - >死锁。

现在,如果您更改了查询,连接将以相同的顺序锁定密钥,即:

  • 连接1:锁定键(1),锁定键(2);

  • 连接2:锁定键(1),锁定键(2);

陷入僵局是不可能的。

所以这就是我的建议:

  1. 除了delete语句之外,确保没有其他任何锁定访问多个密钥的查询。如果你这样做(我怀疑你这样做),请按升序排列他们的WHERE(k1,k2,.. kn)。

  2. 修复delete语句以升序工作:

更改

DELETE FROM onlineusers WHERE datetime <= now() - INTERVAL 900 SECOND

DELETE FROM onlineusers WHERE id IN (SELECT id FROM onlineusers    WHERE datetime <= now() - INTERVAL 900 SECOND order by id) u;

另外要记住的是mysql文档建议在遇到死锁的情况下,客户端应该自动重试。您可以将此逻辑添加到客户端代码中。(比如,在放弃之前对此特定错误进行3次重试)。


查看完整回答
反对 回复 2019-08-06
?
慕桂英3389331

TA贡献2036条经验 获得超8个赞

delete语句很可能会影响表中总行数的很大一部分。最终,这可能会导致在删除时获取表锁。持有锁(在这种情况下是行锁或页锁)并获得更多锁定始终是一种死锁风险。但是我无法解释为什么insert语句导致锁升级 - 它可能与页面拆分/添加有关,但是更好地了解MySQL的人必须填写那里。

首先,可以尝试立即为delete语句显式获取表锁。


查看完整回答
反对 回复 2019-08-06
  • 3 回答
  • 0 关注
  • 1007 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信