在SQLAlchemy中处理mysql重启

在SQLAlchemy中处理mysql重启,mysql,error-handling,sqlalchemy,pylons,Mysql,Error Handling,Sqlalchemy,Pylons,My Pylons应用程序通过SQLAlchemy和python MySQLdb使用本地MySQL服务器。当服务器重新启动时,开放池连接显然是关闭的,但应用程序不知道这一点,而且当它尝试使用这种连接时,它显然会收到“MySQL服务器已离开”: 此异常在任何地方都不会被捕获,因此用户会发现它。如果我应该在代码中的某个地方处理此异常,请在Pylons WSGI应用程序中显示此类代码的位置。或者SA本身可能有一个解决方案?请参见底部的编辑以了解测试的解决方案 我没有试过,但也许使用是一种方法 你可以这

My Pylons应用程序通过SQLAlchemy和python MySQLdb使用本地MySQL服务器。当服务器重新启动时,开放池连接显然是关闭的,但应用程序不知道这一点,而且当它尝试使用这种连接时,它显然会收到“MySQL服务器已离开”:


此异常在任何地方都不会被捕获,因此用户会发现它。如果我应该在代码中的某个地方处理此异常,请在Pylons WSGI应用程序中显示此类代码的位置。或者SA本身可能有一个解决方案?

请参见底部的编辑以了解测试的解决方案

我没有试过,但也许使用是一种方法

你可以这样做:

class MyListener(sqlalchemy.interfaces.PoolListener):
    def __init__(self):
       self.retried = False
    def checkout(self, dbapi_con, con_record, con_proxy):
       try:
           dbapi_con.info() # is there any better way to simply check if connection to mysql is alive?
       except sqlalchemy.exc.OperationalError:
           if self.retried:
               self.retried = False
               raise # we do nothing
           self.retried = True
           raise sqlalchemy.exc.DisconnectionError

# next, code according to documentation linked above follows

e = create_engine("url://", listeners=[MyListener()])
这样,每次连接即将从池中签出时,我们都会测试它是否实际连接到服务器。如果没有,我们给sqlalchemy一个重新连接的机会。之后,如果问题仍然存在,我们就放手了

附言:我没有测试这是否有效

编辑:对于挂架,需要在您的_app.model.init_模型(挂架0.9.7)或您的_app.config.environment.load_环境(挂架1.0)函数中对上面显示的引擎初始化进行修改-这些是创建引擎实例的地方

编辑

好的。我能够再现所描述的情况。上面的代码需要一些更改才能工作。下面是应该如何做。此外,无论是0.9.7还是1.0都无关紧要。

您需要编辑_app/config/environment.py。将这些导出放在文件的顶部:

import sqlalchemy
import sqlalchemy.interfaces
import _mysql_exceptions
加载结束_环境函数应如下所示:

class MyListener(sqlalchemy.interfaces.PoolListener):
    def __init__(self):
       self.retried = False
    def checkout(self, dbapi_con, con_record, con_proxy):
       try:
           dbapi_con.cursor().execute('select now()')
       except _mysql_exceptions.OperationalError:
           if self.retried:
               self.retried = False
               raise
           self.retried = True
           raise sqlalchemy.exc.DisconnectionError

config['sqlalchemy.listeners'] = [MyListener()]

engine = engine_from_config(config, 'sqlalchemy.')
init_model(engine)

这次我能够测试它(在Pylons 1.0+SQLAlchemy 0.6.1上),并且它可以工作。:)

您可以使用SQLAlchemy代理对每个sql查询进行异常处理:

from sqlalchemy.interfaces import ConnectionProxy
class MyProxy(ConnectionProxy):
    def cursor_execute(self, execute, cursor, statement, parameters, context, executemany):
        try:
            return execute(cursor, statement, parameters, context)
        except sqlalchemy.exc.OperationalError:
            # Handle this exception
            pass
要连接此代理,必须在config/environment.py中执行此操作

engine = engine_from_config(config, 'sqlalchemy.', proxy=MyProxy())
或者为每个http查询编写异常处理中间件:

class MyMiddleware(object):
    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        try:
            return self.app(environ, start_response)
        except sqlalchemy.exc.OperationalError:
            start_response(
                '500 Internal Server Error',
                [('content-type', 'text/html')])
            return ['error page\n']
要根据需要或仅在config/middleware.py中按堆栈顺序连接此中间件,请执行以下操作:

# CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
app = MyMiddleware(app)

谢谢,这里也有类似的解决方案:它对我很有用。注意,SQLAlchemy 0.7-
PoolListener
已被弃用,但同样的解决方案也可以使用新的解决方案来实现。另一个问题显示了如何使用robots.jpg在之前的评论中指出的新事件系统实现此功能。2017年回答:使用该功能(SQLAlchemy v1.2.0中新增)。
# CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
app = MyMiddleware(app)