63

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

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

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

4

7 回答 7

51

我以前遇到过这个问题,并且发现处理它的方法是不保留会话。问题是你试图保持连接打开太久。__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 “消失”,您需要解决连接池保持连接打开时间过长并为您检查旧连接的问题。

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

于 2011-06-24T20:13:05.600 回答
37

我有一个类似的问题,但对我来说,我会在每次会话的 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-OCT-08

配置键'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}
于 2016-03-05T21:00:25.080 回答
28

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

连接池 pre-ping - 连接池现在包括一个可选的“pre ping”功能,该功能将为每次连接检查测试池连接的“活跃性”,如果数据库断开连接,则透明地回收 DBAPI 连接。此功能消除了对“池回收”标志的需要以及在数据库重新启动后使用池连接时引发的错误问题。

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

engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)
于 2017-07-13T11:12:58.810 回答
6

如果您使用的是 Flask-SQLAlchemy:

似乎可以修复:https ://github.com/mitsuhiko/flask-sqlalchemy/issues/2

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

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

于 2013-01-20T11:41:34.043 回答
6

@wim 描述的悲观方法

pool_pre_ping=真

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

SQLALCHEMY_POOL_PRE_PING = 真

于 2019-11-12T15:03:07.340 回答
1

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

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

于 2018-06-25T01:00:45.553 回答
0

如果你使用Pool,你应该设置recyle小于DB wait_timeout的wait_timeout是60。所以我设置40来recyle

from sqlalchemy.pool import Pool
pool.QueuePool(self.get_connection, max_overflow=0,pool_size=40,recycle=50)
于 2019-05-03T10:18:26.850 回答