【问题标题】:Avoiding "MySQL server has gone away" on infrequently used Python / Flask server with SQLAlchemy使用 SQLAlchemy 在不经常使用的 Python / Flask 服务器上避免“MySQL 服务器已消失”
【发布时间】:2011-09-22 05:28:28
【问题描述】:

如果不存在,如何配置 Flask / SQLAlchemy 以创建新的数据库连接?

我有一个不常访问的 Python / Flask 服务器,它使用 SQLAlchemy。它每隔几天就会被访问一次,并且在第一次访问时它经常会抛出一个“MySQL 服务器已经消失”的错误。后续的页面浏览量都很好,但是出现这个初始错误看起来很不专业。

我想知道处理此问题的正确方法 - 像“请假很长时间”这样的建议(在这种情况下大约需要 4 天)似乎不正确。如何测试是否缺少数据库连接并在需要时创建一个?

【问题讨论】:

    标签: python mysql sqlalchemy flask database-connection


    【解决方案1】:

    我以前遇到过这个问题,发现处理它的方法是不保留会话。问题是您试图保持连接打开的时间过长。相反,请在 __init__.py 或在任何地方导入的实用程序包中使用线程本地范围会话:

    from sqlalchemy.orm import scoped_session, sessionmaker
    Session = scoped_session( sessionmaker() )
    

    然后设置您的引擎和元数据一次。这允许您在每次连接/断开连接时跳过配置机制。之后,您可以像这样进行数据库工作:

    session = Session()
    someObject = session.query( someMappedClass ).get( someId )
    # use session like normal ...
    session.close()
    

    如果您想保留旧对象并且不想让会话保持打开状态,那么您可以使用上述模式并像这样重用旧对象:

    session = Session()
    someObject = session.merge( someObject )
    # more db stuff
    session.close()
    

    关键是,您要打开会话,完成工作,然后关闭会话。这很好地避免了超时。 .merge 和 .add 有很多选项,允许您包含对分离对象所做的更改或从数据库加载新数据。文档非常冗长,但是一旦您知道要查找的内容,可能会更容易找到。

    要真正做到这一点并防止 MySQL “消失”,您需要解决连接池保持连接打开时间过长并为您检查旧连接的问题。

    要获得新的连接,您可以在create_engine 调用中设置pool_recycle 选项。将此pool_recycle 设置为您希望创建新连接而不是返回现有连接的签出之间连接池中的时间秒数。

    【讨论】:

    • 感谢您的回答,我已经编辑了我的代码,因此它使用了 scoped_session 并且使用数据库的每条路由都以 session = Session() 开头并以 session.close() 结尾。不过,我仍然遇到同样的问题 - 会不会是其他问题?
    • 听起来你可能需要设置一个 pool_recycle 时间——我编辑了我的答案。
    • 为清楚起见,您需要答案的两个元素(原始和更新)来解决此问题。
    【解决方案2】:

    我遇到了类似的问题,但对我来说,我会在每次会话的 5 分钟到 2 小时之间出现“MySQL 已消失”错误。

    我正在使用 Flask-SQLAlchemy,所以它应该关闭空闲连接,但似乎没有这样做,除非连接空闲超过几个小时。

    最终我将其缩小到以下 Flask-SQLAlchemy 设置:

    app.config['SQLALCHEMY_POOL_SIZE'] = 100
    app.config['SQLALCHEMY_POOL_RECYCLE'] = 280
    

    它们的默认设置分别为 10 和 7200(2 小时)。

    这是一个玩弄这些设置以适应您的环境的问题。

    例如,我在很多地方读到 SQLALCHEMY_POOL_RECYCLE 应该设置为 3600,但这对我不起作用。我使用 PythonAnywhere 托管,它们会在 5 分钟(300 秒)后终止空闲的 MySQL 连接。所以将我的值设置为小于 300 解决了这个问题。

    我希望这对其他人有帮助,因为我在这个问题上浪费了太多时间。

    http://flask-sqlalchemy.pocoo.org/2.1/config/#configuration-keys

    更新:2019 年 10 月 8 日

    配置键 'SQLALCHEMY_POOL_SIZE''SQLALCHEMY_POOL_RECYCLE' 自 v2.4 起已弃用,并将在 SQLAlchemy v3.0 中删除。使用'SQLALCHEMY_ENGINE_OPTIONS' 设置相应的值。

    app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {'pool_size' : 100, 'pool_recycle' : 280}
    

    【讨论】:

    • 我们的文档中实际上有一个关于 pool_recycle 值的页面:help.pythonanywhere.com/pages/UsingSQLAlchemywithMySQL
    • 这篇文章的更新部分非常有用。谢谢你。你拯救了我的一天
    • 他们是否有理由“弃用”它,只是让它成为一个更模糊的子选项?或者 v3 是否带有一些实际上使这变得不必要的功能?
    【解决方案3】:

    2018 年回答:在 SQLAlchemy v1.2.0+ 中,您可以使用 connection pool pre-ping 功能来解决“MySQL 服务器已消失”的问题。

    连接池预 ping - 连接池现在包括一个 可选的“pre ping”功能,将测试池的“活跃度” 每次连接结帐的连接,透明地回收 如果数据库断开连接,则连接 DBAPI。这项特征 消除了对“池回收”标志以及问题的需要 在数据库之后使用池连接时引发的错误 重启。

    使用新参数可以在结帐时对连接进行悲观测试:

    engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)
    

    【讨论】:

    【解决方案4】:

    如果您使用的是 Flask-SQLAlchemy:

    似乎有可用的修复程序:https://github.com/mitsuhiko/flask-sqlalchemy/issues/2

    遗憾的是,默认安装(pip install flask-sqlalchemy)还没有正确应用补丁,尤其是在这个问题上:https://github.com/e-dard/flask-sqlalchemy/commit/cf659f346e005d34257d256fa4c42889741fc31f

    从 github 获取最新版本应该可以修复它。

    【讨论】:

    • 如果您不想使用 Flask-SQLAlchemy 的前沿技术,您可以将 SQLALCHEMY_POOL_RECYCLE 配置值设置为 7200。
    【解决方案5】:

    @wim 描述的悲观方法

    pool_pre_ping=真

    现在可以使用配置变量为 Flask-SQLAlchemy 完成 -->

    SQLALCHEMY_POOL_PRE_PING = 真

    【讨论】:

      【解决方案6】:

      当我遇到这个错误时,我正在存储一个大小约为 1MB 的 LONGBLOB / LargeBinary 图像。我不得不调整 MySQL 中的 max_allowed_packet 配置设置。

      我用mysqld --max-allowed-packet=16M

      【讨论】:

        【解决方案7】:

        如果使用 Pool,则应将 recyle 设置为小于 DB 的 wait_timeout wait_timeout 是 60。所以我设置了 40 来回收

        from sqlalchemy.pool import Pool
        pool.QueuePool(self.get_connection, max_overflow=0,pool_size=40,recycle=50)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-03-14
          • 1970-01-01
          • 2013-12-31
          • 2021-02-09
          • 1970-01-01
          • 2015-04-05
          • 2018-12-27
          • 1970-01-01
          相关资源
          最近更新 更多