9

我有一个 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')

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

  • 这个问题MySQL中,其中一条评论建议每隔一段时间对服务器进行一次 ping操作以保持它(连接?)处于活动状态。不过,我不确定如何通过 ORM 做到这一点。(我应该只是SELECT 1每小时一次吗?)
  • 在4 个月前打开的这个 github peewee issue中,提到了同样的错误,不过,据说那里已经解决了(我正在使用更新的版本)。
  • 在一个7 年的问题trac,一个建议是增加MySQL3 天的超时时间。
  • 在这个论坛讨论中,建议增加MySQL的超时选项,但提供了“使用 MySQL JDBC 连接器的 autoReconnect 选项”的替代方案。我试图弄清楚 Python 的MySQLdb模块是否存在这样的选项,但找不到。
  • 我找到了这个关于重新连接行为的MySQL 参考页面,但对于我的理解来说有点复杂MySQL(通常我只使用 ORM),而且我不知道如何从peewee.

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

4

3 回答 3

7

我遇到了同样的问题,对于使用 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 功能在哪里:

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

长时间空闲的客户端可以使用此功能,检查服务器是否已关闭连接,并在必要时重新连接。

1.2.2 中的新功能:接受可选的重新连接参数。如果为 True,则客户端将尝试重新连接。请注意,此设置是持久的。默认情况下,这在 MySQL<5.0.3 中打开,之后关闭。

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

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

于 2014-10-22T12:55:48.660 回答
5

You have to catch the exception and based on which error, reconnect or to do something else. Whether it is a connection time out, or a network problem or the MySQL had to be restarted.

The below (pseudoish) code shows how you could do that, but there is more to it. You'll want to try a few times and then bail out, or maybe try every 2 minutes or so.

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

Does not really matter whether you use an ORM or not. However, an ORM might offer this functionality.

于 2014-02-20T09:11:28.113 回答
0

我已经解决了这个问题。

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

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

from peewee import *
from playhouse.pool import *
于 2014-08-02T01:49:53.410 回答