25

错误OperationalError: (OperationalError) (2006, 'MySQL server has gone away')我在 Flask 上编码项目时已经收到此错误,但我不明白为什么会收到此错误。

我有这样的代码(是的,如果代码小且执行速度快,那么没有错误)

db_engine = create_engine('mysql://root@127.0.0.1/mind?charset=utf8', pool_size=10, pool_recycle=7200)
Base.metadata.create_all(db_engine)

Session = sessionmaker(bind=db_engine, autoflush=True)
Session = scoped_session(Session)
session = Session()

# there many classes and functions

session.close()

这段代码返回错误'MySQL server has gone away',但一段时间后,当我在脚本中使用暂停时返回它。

Mysql 我从 openserver.ru 使用(它是 web 服务器,例如 wamp)。

谢谢..

4

6 回答 6

20

SQLAlchemy 现在有一篇关于如何使用 ping 对连接的新鲜度持悲观态度的文章:

http://docs.sqlalchemy.org/en/latest/core/pooling.html#disconnect-handling-pessimistic

从那里,

from sqlalchemy import exc
from sqlalchemy import event
from sqlalchemy.pool import Pool

@event.listens_for(Pool, "checkout")
def ping_connection(dbapi_connection, connection_record, connection_proxy):
    cursor = dbapi_connection.cursor()
    try:
        cursor.execute("SELECT 1")
    except:
        # optional - dispose the whole pool
        # instead of invalidating one at a time
        # connection_proxy._pool.dispose()

        # raise DisconnectionError - pool will try
        # connecting again up to three times before raising.
        raise exc.DisconnectionError()
    cursor.close()

并进行测试以确保上述工作正常:

from sqlalchemy import create_engine
e = create_engine("mysql://scott:tiger@localhost/test", echo_pool=True)
c1 = e.connect()
c2 = e.connect()
c3 = e.connect()
c1.close()
c2.close()
c3.close()

# pool size is now three.

print "Restart the server"
raw_input()

for i in xrange(10):
    c = e.connect()
    print c.execute("select 1").fetchall()
    c.close()
于 2013-07-22T15:10:57.007 回答
18

查看 mysql 文档,我们可以看到发生此错误的原因有很多。但是,我看到的两个主要原因是:


1)最常见的原因是超过8小时未使用连接已断开连接(默认设置)

默认情况下,如果没有发生任何事情,服务器会在八小时后关闭连接。您可以通过在启动 mysqld 时设置 wait_timeout 变量来更改时间限制

为了完整起见,我将提到两种处理方法,但它们已经在其他答案中提到:

A : 我有一份很长的工作,所以我的连接是陈旧的。为了解决这个问题,我刷新了我的连接:

create_engine(conn_str, pool_recycle=3600)  # recycle every hour

B : 我有一个长期运行的服务和长期不活动。为了解决这个问题,我在每次调用之前 ping mysql:

create_engine(conn_str, pool_pre_ping=True)

2)我的数据包太大,应该会抛出这个错误:

_mysql_exceptions.OperationalError: (1153, "Got a packet bigger than 'max_allowed_packet' bytes")

我只看到这个隐藏在跟踪的中间,虽然通常你只会看到通用的_mysql_exceptions.OperationalError (2006, 'MySQL server has gone away'),所以很难捕捉到,特别是如果日志在多个地方。

上面的文档说最大数据包大小默认为64MB,但实际上是16MB,可以用SELECT @@max_allowed_packet

要解决此问题,请减小INSERTorUPDATE调用的数据包大小。

于 2019-03-12T17:55:04.883 回答
2

我刚刚遇到了同样的问题,通过一些努力解决了。希望我的经验对其他人有所帮助。

考虑到一些建议,我使用了连接池并设置pool_recycle了 less than wait_timeout,但它仍然不起作用。

然后,我意识到全局会话可能只是使用相同的连接,而连接池不起作用。为了避免全局会话,为每个请求生成一个新会话,该会话Session.remove()在处理后被删除。

最后,一切都很好。

于 2016-04-13T07:32:46.367 回答
1

文档中您可以使用pool_recycle参数:

from sqlalchemy import create_engine
e = create_engine("mysql://scott:tiger@localhost/test", pool_recycle=3600)
于 2014-12-23T10:41:03.030 回答
0

要记住的另一点是使用数据库初始化手动推送烧瓶应用程序上下文。这应该可以解决问题。

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

app = Flask(__name__)
with app.app_context():
    db.init_app(app)
于 2020-02-27T17:01:58.623 回答
-1

https://docs.sqlalchemy.org/en/latest/core/pooling.html#disconnect-handling-optimistic

 def sql_read(cls, sql, connection):
    """sql for read action like select
    """
    LOG.debug(sql)
    try:
        result = connection.engine.execute(sql)
        header = result.keys()
        for row in result:
            yield dict(zip(header, row))
    except OperationalError as e:
        LOG.info("recreate pool duo to %s" % e)
        connection.engine.pool.recreate()
        result = connection.engine.execute(sql)
        header = result.keys()
        for row in result:
            yield dict(zip(header, row))
    except Exception as ee:
        LOG.error(ee)
        raise SqlExecuteError()
于 2019-04-11T11:40:54.023 回答