OperationalError:MySQL连接不可用

Pak*_*man 11 python mysql sqlalchemy flask flask-sqlalchemy

我正在使用Flask-SQLAlchemy 1.0,Flask 0.10,SQLAlchemy 0.8.2和Python 2.7.5.我正在使用Oracle的MySQL Connector/Python 1.0.12连接MySQL 5.6.

当我重新启动我的Web服务器(Apache2或Flask的内置)时,我OperationalError: MySQL Connection not available在MySQL wait_timeout过期后收到异常(默认为8小时).

我发现有类似问题并明确设置的人SQLALCHEMY_POOL_RECYCLE = 7200,即使这是Flask-SQLAlchemy的默认设置.当我在这里放置断点时,我看到拆解功能session.remove()在每个请求后成功调用.有任何想法吗?

2014年7月21日更新:

由于这个问题继续受到关注,我必须补充一点,我确实尝试了一些提案.我的两次尝试看起来如下:

第一:

@contextmanager
def safe_commit():
    try:
        yield
        db.session.commit()
    except:
        db.session.rollback()
        raise
Run Code Online (Sandbox Code Playgroud)

这允许我像这样包装我的提交调用:

with safe_commit():
    model = Model(prop=value)
    db.session.add(model)
Run Code Online (Sandbox Code Playgroud)

我99%肯定我没有错过db.session.commit这种方法的任何电话,我仍然有问题.

第二:

def managed_session():
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            try:
                response = f(*args, **kwargs)
                db.session.commit()
                return response
            except:
                db.session.rollback()
                raise
            finally:
                db.session.close()
        return decorated_function
    return decorator
Run Code Online (Sandbox Code Playgroud)

为了进一步确保我没有丢失任何提交调用,我创建了一个Flask包装器,启用了代码(如果我没记错的话):

@managed_session()
def hello(self):
    model = Model(prop=value)
    db.session.add(model)

    return render_template(...
Run Code Online (Sandbox Code Playgroud)

不幸的是,这两种方 我还记得尝试发出SELECT(1)调用以尝试重新建立连接,但我不再拥有该代码.

对我来说,底线是MySQL/SQL Alchemy有问题.当我迁移到Postgres时,我不必担心我的提交.一切正常.

Lou*_*u K 6

我遇到了这个问题,这让我疯了.我尝试使用SQLALCHEMY_POOL_RECYCLE,但这似乎没有解决问题.

我终于找到了http://docs.sqlalchemy.org/en/latest/orm/session.html#when-do-i-construct-a-session-when-do-i-commit-it-and-when-do -i-close-it,适用于flask-sqlalchemy.

在我开始使用以下模式后,我没有看到问题.关键似乎总是确保a commit()或者rollback()被执行.因此,如果存在if-then-else但是没有流过commit()(例如,对于检测到的错误),也可以在重定向,abort,render_template调用之前commit()rollback()之前执行.

class DoSomething(MethodView):
    def get(self):
        try:
            # do stuff
            db.session.commit()
            return flask.render_template('sometemplate.html')
        except:
            db.session.rollback()
            raise
app.add_url_rule('/someurl',view_func=DoSomething.as_view('dosomething'),methods=['GET'])
Run Code Online (Sandbox Code Playgroud)

更新2014年7月22日

我发现我还必须将SQLALCHEMY_POOL_RECYCLE更改为小于MySQL interactive_timeout.在godaddy服务器上,interactive_timeout设置为60,所以我将SQLALCHEMY_POOL_RECYCLE设置为50.我认为我使用的模式和此超时都是使问题消失所必需的,但此时我并不积极.但是,我很确定当SQLALCHEMY_POOL_RECYCLE大于interactive_timeout时,我仍然遇到操作错误.


xys*_*sun 1

sqlalchemy提供了2种处理断线的方法,详情见文档

简洁版本:

  • 乐观地

使用try...except块来捕获断开连接异常。这将500在请求失败时返回 a,然后 Web 应用程序将继续正常运行。因此,如果不经常发生断开连接,请使用此方法。注意:您需要将每个可能失败的操作包装在try...except块中。

  • 悲观地(我正在使用的)

基本上每次从池中检出连接时都会执行额外的ping操作(类似于)。SELECT 1如果ping失败 raise DisconnectionError,主机池将尝试强制创建新连接(事实上,池在正式放弃之前会尝试 3 次)。这样您的应用程序就不会看到500错误。代价是执行额外的 SQL,尽管根据文档,开销很小。