Postgresql 如何使Flask SQLAlchemy重用数据库连接?

Postgresql 如何使Flask SQLAlchemy重用数据库连接?,postgresql,sqlalchemy,flask,flask-sqlalchemy,Postgresql,Sqlalchemy,Flask,Flask Sqlalchemy,我似乎无法让我的Flask应用程序关闭或重新使用DB连接。我正在使用PostgreSQL 9.1.3和 Flask==0.8 Flask-SQLAlchemy==0.16 psycopg2==2.4.5 当我的测试套件运行时,打开的连接数逐渐增加,直到达到20(在postgresql.conf中设置max_connections),然后我看到: OperationalError: (OperationalError) FATAL: sorry, too many clients alread

我似乎无法让我的Flask应用程序关闭或重新使用DB连接。我正在使用PostgreSQL 9.1.3和

Flask==0.8
Flask-SQLAlchemy==0.16
psycopg2==2.4.5
当我的测试套件运行时,打开的连接数逐渐增加,直到达到20(在
postgresql.conf
中设置
max_connections
),然后我看到:

OperationalError: (OperationalError) FATAL:  sorry, too many clients already
 None None
我已经将代码缩减到只调用
create\u all
drop\u all
(但没有发出任何sql,因为没有模型)

我在日志中看到正在签入和签出连接:

DEBUG:sqlalchemy.pool.QueuePool:Connection <connection object at 0x101c1dff0; dsn: 'dbname=cx_test host=localhost', closed: 0> checked out from pool
DEBUG:sqlalchemy.pool.QueuePool:Connection <connection object at 0x101c1dff0; dsn: 'dbname=cx_test host=localhost', closed: 0> being returned to pool
WARNING:root:impl   <-------- That's the test running
DEBUG:sqlalchemy.pool.QueuePool:Connection <connection object at 0x101c1dff0; dsn: 'dbname=cx_test host=localhost', closed: 0> checked out from pool
DEBUG:sqlalchemy.pool.QueuePool:Connection <connection object at 0x101c1dff0; dsn: 'dbname=cx_test host=localhost', closed: 0> being returned to pool
这是我第一次在flask中使用应用程序工厂,我复制了部分源代码。这些文档提到在错误的上下文中使用db会导致连接泄漏-可能我的初始化操作不正确?

您知道在每个
测试方法之前和之后都会调用。从您的代码来看,您似乎需要它们来确保数据库为空。
但是,也有,每个测试类调用一次。

我相信您可以拆分当前拥有的代码,并将
db连接
相关部分移动到
级别,同时将
测试方法
相关部分保留在需要的位置。

由于问题大约在一年前提出,我想OP一定已经解决了他的问题。但对于那些游荡到这里(像我一样)试图弄清楚到底发生了什么的人来说,以下是我最好的解释:

正如van所说,问题确实在于测试用例为每个测试调用
setUp
tearDown
。虽然连接并非完全从SQLAlchemy泄漏,而是因为每个测试都有自己的
设置
,所以创建了应用程序的多个实例:每个应用程序都有自己的数据库连接池,可能在测试完成时不会重用或回收

换句话说,该连接正在被签出并正确返回到池,但该连接将作为空闲连接继续存在,以便在相同的应用程序(连接池点)内进行未来交易


在上面的测试用例中,创建了大约20个连接池(由于create/drop___all,每个连接池都有一个空闲连接),并占用了postgres连接限制。

在阅读了SQLAlchemy文档并对db实例进行了一些修改之后,我终于找到了解决方案。在
tearDown()
中添加
db.get\u引擎(self.app).dispose()
,使其看起来像:

def tearDown(self):
    db.session.remove()
    db.drop_all()
    db.get_engine(self.app).dispose()
    self._ctx.pop()

编辑:SQLALCHEMY在2.4.3版中的Flask SQLALCHEMY中不推荐在拆卸时提交SQLALCHEMY。您可以在此处看到更改说明,建议您自己调用
.commit()

我要做的是注册我自己的
应用程序。如果响应状态代码<400,在请求后调用
.commit()
。这要求您正确地构造应用程序,以确保响应状态代码<400的HTTP事务应提交到数据库,但我认为这是一个很好的设计原则

----下面是过时的答案----

在Flask SQLAlchemy的最新版本中,
session.remove()
app.after\u request
中自动调用

另外,请参见此处的
SQLALCHEMY\u-COMMIT\u-ON\u-TEARDOWN
设置:


这也将自动提交事务。

谢谢Van-这解决了测试套件的问题,但这不只是意味着我泄漏的连接更少吗?@TomDunham:我想你是对的。没有
postgres
,因此无法帮助您,抱歉。。
def tearDown(self):
    db.session.remove()
    db.drop_all()
    db.get_engine(self.app).dispose()
    self._ctx.pop()