我有一个记录在线用户的innoDB表。用户每次刷新页面时都会对其进行更新,以跟踪他们所访问的页面以及它们对该站点的最后访问日期。然后,我会有一个cron,每15分钟运行一次,以删除旧记录。
我在尝试获取锁时发现了“死锁;昨晚尝试重新启动事务”大约5分钟,这似乎是在向该表中运行INSERT时出现的情况。有人可以建议如何避免此错误吗?
===编辑===
以下是正在运行的查询:
首次访问网站:
INSERT INTO onlineusers SET ip = 123.456.789.123, datetime = now(), userid = 321, page = '/thispage', area = 'thisarea', type = 3 在每个页面上刷新:
UPDATE onlineusers SET ips = 123.456.789.123, datetime = now(), userid = 321, page = '/thispage', area = 'thisarea', type = 3 WHERE id = 888 每15分钟Cron:
DELETE FROM onlineusers WHERE datetime <= now() - INTERVAL 900 SECOND 然后,它会做一些计数来记录一些统计信息(即:在线成员,在线访客)。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
一个可以解决大多数僵局的简单技巧就是按特定顺序对操作进行排序。
当两个事务试图以相反的顺序锁定两个锁时,会出现死锁,即:
连接1:锁定键(1),锁定键(2); 连接2:锁定键(2),锁定键(1); 如果两个都同时运行,则连接1将锁定键(1),连接2将锁定键(2),每个连接将等待另一个释放键->死锁。
现在,如果您更改查询以使连接以相同的顺序锁定键,即:
连接1:锁定键(1),锁定键(2); 连接2:锁键(1),锁键(2); 陷入僵局是不可能的。
所以这是我的建议:
确保除了delete语句外,没有其他一次锁定访问多个键的查询。如果您这样做(我怀疑您这样做),请按升序在(k1,k2,.. kn)中订购他们的WHERE。
修复您的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个重试此特定错误)。来源:stack overflow