在超时时重新连接MySQL

时间:2014-02-18 11:45:11

标签: python mysql orm mysql-python peewee

我有一个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中,其中一条评论建议每隔一段时间ping MySQL服务器以保持它(连接?)活着。不过,我不知道如何通过ORM来做到这一点。 (我应该每小时SELECT 1,比方说?)
  • 在4个月前开放的this github peewee issue中,引用了相同的错误,但声称它已解决(我使用的是较新的版本)。
  • trac MySQL中,有一项建议是将MySQL的超时时间延长3天。
  • 在这个7 year old issue中,建议增加MySQLdb超时的选项,但是使用mysql JDBC连接器的自动重新连接选项""提供。我试图弄清楚Python MySQL模块是否存在这样的选项,但无法找到。
  • 我在重新连接行为中找到了这个forum discussion,但我对peewee的理解有点复杂(通常我只与ORM合作),我不知道如何应用MySQL
  • 中的任何一项

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

3 个答案:

答案 0 :(得分:8)

我有同样的问题,对于使用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中的新功能:接受可选的重新连接参数。如果是,那么   客户端将尝试重新连接。请注意,此设置为   执着。默认情况下,这在MySQL< 5.0.3中开启,之后关闭。

     

非标。您应该假设ping()执行隐式   回滚;仅在开始新交易时使用。你去过   警告。

db.get_conn().ping.__doc__中的

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

答案 1 :(得分:5)

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

以下(伪)代码显示了如何做到这一点,但还有更多。你想尝试几次然后拯救,或者每2分钟左右尝试一次。

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

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

答案 2 :(得分:0)

我已经解决了这个问题。

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

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

from peewee import *
from playhouse.pool import *