超时重新连接 MySQL

Posted

技术标签:

【中文标题】超时重新连接 MySQL【英文标题】:Reconnecting MySQL on timeout 【发布时间】:2014-03-18 03:31:24 【问题描述】:

我有一个 Python 程序,它在后台运行数周,并且每隔一段时间进行一次数据库查询。为此,我正在使用 ORM peewee(版本 2.2.1)。我使用mysql 作为后端。

最近我在访问数据库时遇到了一个反复出现的问题,通常是在运行程序几天之后。 peewee 引发的错误是

peewee.OperationalError: (2006, 'MySQL server has gone away')

回溯在peewee 深处。我把它贴在这里,但由于我的virtualenv 使文件名太长,我正在缩短它们:

  File ".../local/lib/python2.7/site-packages/peewee.py", line 2910, in save
    ret_pk = self.insert(**field_dict).execute()
  File ".../local/lib/python2.7/site-packages/peewee.py", line 2068, in execute
    return self.database.last_insert_id(self._execute(), self.model_class)
  File ".../local/lib/python2.7/site-packages/peewee.py", line 1698, in _execute
    return self.database.execute_sql(sql, params, self.require_commit)
  File ".../local/lib/python2.7/site-packages/peewee.py", line 2232, in execute_sql
    self.commit()
  File ".../local/lib/python2.7/site-packages/peewee.py", line 2104, in __exit__
    reraise(new_type, new_type(*exc_value.args), traceback)
  File ".../local/lib/python2.7/site-packages/peewee.py", line 2223, in execute_sql
    res = cursor.execute(sql, params or ())
  File ".../local/lib/python2.7/site-packages/MySQLdb/cursors.py", line 205, in execute
    self.errorhandler(self, exc, value)
  File ".../local/lib/python2.7/site-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
peewee.OperationalError: (2006, 'MySQL server has gone away')

我发现的可能的解决方案尝试:

在this question 中,其中一位cmets 建议每隔一段时间对MySQL 服务器进行一次ping 操作,以使其(连接?)保持活动状态。不过,我不确定如何通过 ORM 做到这一点。 (我应该每小时简单地SELECT 1 吗?) 在 4 个月前打开的 this github peewee issue 中,提到了相同的错误,但声称已解决(而且我使用的是更新版本)。 在trac 的7 year old issue 中,一个建议是将MySQL 的超时时间延长3 天。 在此forum discussion 中,建议选择增加MySQL 的超时时间,但提供了“使用 MySQL JDBC 连接器的 autoReconnect 选项”的替代方案。我试图弄清楚 Python 的 MySQLdb 模块是否存在这样的选项,但找不到。 我在重新连接行为上找到了这个MySQL reference page,但是对于我对MySQL 的理解来说有点复杂(通常我只使用ORM),我不知道如何从@987654341 应用它@。

即使我能够 ping 数据库以使连接保持更长时间的活动,我认为在不需要连接时保持连接活动被认为是一种不好的做法。有没有办法通过 ORM 重新打开连接?我认为 ping 和增加 MySQL 的超时作为解决方法,而真正的解决方案是在需要时重新连接(真正的解决方案是我所要求的)。

【问题讨论】:

查看MySQL中wait_timeout的值 我猜是8小时;这不是默认的吗? 连接完成后只需手动调用db.close() 我从来没有“完成”它;该程序只是继续运行。尽管如此,如果我不使用连接,我认为保持连接不是一个好习惯。我设置的任何超时都可能不够大。 【参考方案1】:

您必须捕获异常并根据哪个错误重新连接或执行其他操作。无论是连接超时,还是网络问题或 MySQL 必须重新启动。

下面的(伪)代码显示了如何做到这一点,但还有更多。您可能想尝试几次然后退出,或者每 2 分钟左右尝试一次。

while True:
    try:
        # do your database stuff
    except peewee.OperationalError as exc:
        # Oops! We have to try to reconnect

是否使用 ORM 并不重要。但是,ORM 可能会提供此功能。

【讨论】:

这看起来确实是正确的做法。然而,这并不容易完成;没有一种方法可以让我用这样的try... except 结构进行包装,每次从不同的地方引发错误。这就是 ORM 的好处——但也存在问题。它们在您的代码中变得几乎透明。无论如何,我最终 ping 了服务器,希望 peewee 有一天人们会实现一个内部可选的重新连接方法。 在这种极端情况下,您可以将 try/except 放在脚本的 main() 方法周围。 不,我永远不会那样做......它不是脚本,它是一个巨大的多线程软件......我只是声称这是ORM的责任,否则我必须“入侵”它的领土,使其变得多余。 我发现通用的“重新连接并重试”方法并不总是有效。特别是如果您正在重试的查询是准备好的语句。如果已准备好,则需要在建立连接后“重新准备”,这可能比您想象的要复杂,具体取决于现有的抽象。【参考方案2】:

我已经解决了这个问题。

我的解决方案是使用来自playhouse.pool模块的mysql连接池PooledMySQLDatabase

请阅读:https://github.com/coleifer/peewee/issues/239

from peewee import *
from playhouse.pool import *

【讨论】:

附注:此模块被认为是实验性的,将其应用于生产可能会很危险。【参考方案3】:

我遇到了同样的问题,对于使用 MySQLdb 的 peewee,我在初始化 MySQL 数据库实例时得到了以下解决方案:

db = MySQLDatabase(db_name, user=db_username, passwd=db_password, host=db_host, port=db_port)
db.get_conn().ping(True)

ping 函数的位置:

检查与服务器的连接是否正常。如果它 已关闭,尝试自动重新连接。

此功能可供长期闲置的客户端使用 while,检查服务器是否关闭了连接 并在必要时重新连接。

1.2.2 中的新功能:接受可选的重新连接参数。如果为真,那么 客户端将尝试重新连接。请注意,此设置是 执着的。默认情况下,在 MySQL

非标准。您应该假设 ping() 执行隐式 回滚;仅在开始新事务时使用。你已经 警告。

db.get_conn().ping.__doc__。请注意,如果您再次创建另一个连接,则必须使用 db.get_conn().ping(True)。因此,如果您重新连接(例如通过 db.connect()),您必须重复 ping。

【讨论】:

在运行查询之前 Ping 被认为是一种浪费资源且不可靠的反模式:percona.com/blog/2010/05/05/… 每次 ping 数据库,都会杀死一只可爱的海豚。

以上是关于超时重新连接 MySQL的主要内容,如果未能解决你的问题,请参考以下文章

JDBC 连接超时无法重新连接

JDBC 连接:超时后未重新连接

mysql客户端重新连接时提示输入密码

oracle闲置超时,怎么样重新连接(急)

mysql连接超时怎么处理

mysql连接超时的问题