【问题标题】:Endless deadlock situation on mySQL innoDBmySQL innoDB 上无休止的死锁情况
【发布时间】:2020-06-09 01:16:02
【问题描述】:

这是我最近在我的 Google Cloud Platform 帐户的虚拟机中托管的 MySQLdb 5.7(带有 innoDB 引擎)中遇到的一个问题。 突然,我的数据库进入一个名为“用户”的特定表上的每个事务(例如登录)都失败(无限超时)的状态。 我犯了这个错误:pymysql.err.OperationalError: (1213, 'Deadlock found when trying to get lock; try restarting transaction'

好吧,基本上我会尝试找出是否可以从这个圈出的情况中自动恢复。我在 MySQL 的网站上读到,默认情况下执行回滚到最后一个事务,但为什么在我的情况下没有发生这种情况?在这种情况下呆了很长时间后,我不得不重新启动 MySQL 服务器。

我需要一些关于如何调查它或采取行动不再面对它的指示,因为它是一个包含客户的实时数据库。

【问题讨论】:

  • 另一个事务持有表/行的锁。尝试使用SHOW ENGINE INNODB STATUS; 或/和select * from information_schema.innodb_lock_waits; 和/或select * from information_schema.innodb_locks; 识别此事务。可能正在运行备份?
  • 感谢您的快速回复!我认为这些查询仅在发生死锁时才显示结果,对吗?如果我想看看到底发生了什么,我该如何在谷歌云平台的错误日志中进行搜索?因为,我没有找到带有“死锁”关键字的记录,也许还有另一种方法可以找到?有没有办法从这种情况中自动恢复?
  • 您能分享一下您在 Google Cloud Platform Logging 中看到的虚拟机错误吗?
  • 嗨!我只是在寻找与死锁或类似问题相关的错误。我只是想找出导致这种无休止僵局的原因。
  • 你好,约翰,这个问题解决了吗?如果不是:根据文档(dev.mysql.com/doc/refman/5.7/en/innodb-deadlocks.html),如果设置了“innodb_deadlock_detect”配置选项(默认情况下),或者如果“innodb_deadlock_detect”未设置并且使用选项定义的值,则会发生回滚“innodb_lock_wait_timeout”(秒数)已用完。

标签: mysql google-cloud-platform google-compute-engine database-deadlocks


【解决方案1】:

MySQL 的 InnoDB 引擎支持行级锁定,即使您的代码插入或更新单行(特别是在要更新的表上有多个索引时),这也可能导致死锁。最好的办法是围绕此设计代码,以便在事务由于死锁而失败时重试事务。 MySQL Official Documentation中提供了一些有关 MySQL 死锁诊断和可能的解决方法的有用信息

【讨论】:

  • 我试图在我的存储过程中设置锁,因为这表明:dev.mysql.com/doc/refman/8.0/en/innodb-deadlocks-handling.html,但我收到消息“存储过程中不允许锁”。你知道什么会导致无限的僵局吗?因为我在互联网上没有找到任何东西......到处都说回滚是自动执行的,但这为什么在我的情况下没有发生?我怎么能弄明白?
  • 您能否分享您的存储过程的代码或 SQL 语句以便进一步调查?谢谢
  • 以上是登录过程的存储过程,我们在其中检测到无限死锁。
【解决方案2】:

下面是我们检测到无限死锁的登录过程的存储过程。

CREATE DEFINER=`root`@`%` PROCEDURE `login`(
    in email1 varchar(45), 
    in password1 varchar(256),
    in lastlogin datetime, 
    out s INT(1)
    )
    BEGIN
    DECLARE p INT(11);
    DECLARE counter TINYINT;

      IF EXISTS (select * from user where user.email = email1 AND user.password = password1 AND user.locked = 0 AND user.inactive = 0) THEN
          SELECT id INTO p FROM user WHERE user.email = email1;
          SELECT user.id, user.id_user_roles, user.id_user_settings, user.first_name, user.last_name, UserRoles.description
          FROM user
          LEFT JOIN UserRoles
          ON user.id_user_roles = UserRoles.id_user_roles WHERE user.id = p;
          UPDATE user SET last_login = lastlogin WHERE user.id = p;
          INSERT INTO login_info (id_user, timestamp)
          VALUES (p, lastlogin);
          SET s = 1; 
      ELSE
          SELECT login_error_times INTO counter FROM user WHERE email = email1;
          IF (counter < 3) THEN
             SET counter = counter + 1;
             UPDATE user
             SET login_error_times = counter
             WHERE user.email = email1;
             SET s = 0; 
          ELSE
             UPDATE user
             SET locked = 1
             WHERE user.email = email1;
             SET s = 2;
          END IF;   
      END IF;
    END

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-29
    • 1970-01-01
    • 2010-10-13
    相关资源
    最近更新 更多