如何使Flask SQLAlchemy重用数据库连接? [英] How do I make Flask SQLAlchemy reuse db connections?

查看:694
本文介绍了如何使Flask SQLAlchemy重用数据库连接?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我似乎无法让我的Flask应用程序关闭或重新使用数据库连接。我使用的是PostgreSQL 9.1.3和

pre $ code $ Flask == 0.8
Flask-SQLAlchemy == 0.16
psycopg2 == 2.4.5

当我的测试套件运行的时候, 20( max_connections 设置在 postgresql.conf 中),然后我看到:

  OperationalError:(OperationalError)致命:对不起,已经有太多客户
无无

我将代码缩减到只是调用 create_all drop_all (但没有发出任何SQL,因为没有模型)。



我看到连接正在进出日志中:

pre $ DEBUG:sqlalchemy.pool.QueuePool:连接<连接对象在0x101c1dff0; dsn:'dbname = cx_test host = localhost',关闭:0>从池中检出
DEBUG:sqlalchemy.pool.QueuePool:连接<连接对象在0x101c1dff0; dsn:'dbname = cx_test host = localhost',关闭:0>被返回到池
警告:root:impl< --------这就是运行
的测试DEBUG:sqlalchemy.pool.QueuePool:连接<连接对象在0x101c1dff0; dsn:'dbname = cx_test host = localhost',关闭:0>从池中检出
DEBUG:sqlalchemy.pool.QueuePool:连接<连接对象在0x101c1dff0; dsn:'dbname = cx_test host = localhost',关闭:0>被返回到池

对于每个测试运行的连接地址(xyz连接对象部分)是不同的。我怀疑这与问题有关,但我不确定如何进一步调查。



下面的代码在新的venv中重现了这个问题:

 从瓶子导入烧瓶
from flask.ext.sqlalchemy从unittest导入SQLAlchemy
TestCase

导入日志
logging.basicConfig(level = logging.DEBUG)
logging.getLogger('sqlalchemy.pool').setLevel(logging.DEBUG)
logging.getLogger('sqlalchemy.engine').setLevel(logging.DEBUG)
logging.getLogger('sqlalchemy .diases').setLevel(logging.DEBUG)
logging.getLogger('sqlalchemy.orm').setLevel(logging.DEBUG)


db = SQLAlchemy()
$ b $ def create_app(config = None):
app = Flask(__ name__)
app.config.from_object(config)
db.init_app(app)
返回应用程序


class AppTestCase(TestCase):
SQLALCHEMY_DATABASE_URI =postgresql:// localhost / cx_test
TESTING = True

def create_app(self):
return create_app(self)
$ b def setUp(self):
self.app = self.create_app()
self.client = self.app.test_client()
self._ctx = self.app.test_request_context()
self._ctx .push()
db.create_all()

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


class TestModel(AppTestCase):
def impl(self):
logging.warn(impl)

$ b $ def test_01(self):
self.impl()

def test_02(self):
self.impl()

def test_03(self):
self.impl()

def test_04(self):
self.impl()

def test_05(self):
self.impl()

def test_06(self):
self.impl()

def test_07(self):
self.impl()

def test_08(self):
self.impl()
$ b $ def test_09(self) :
self.impl()

def test_10(self):
self.impl()

def test_11(self):
self.impl()

def test_12(self ):
self.impl()

def test_13(self):
self.impl()

def test_14(self):
self.impl()

def test_15(self):
self.impl()

def test_16(self):
self。 impl()

def test_17(self):
self.impl()

def test_18(self):
self.impl()

def test_19(self):
self.impl()


$ b if if __name__ ==__main__:
import unittest
unittest.main()

这是我第一次使用app烧瓶中的工厂,我从 Flask-SQLAlchemy文档复制了部分代码。 Elseware 这些文档提到,使用在错误的上下文中的数据库会导致连接泄漏 - 也许我正在做错误的init?

解决方案

在阅读SQLAlchemy文档一些摆脱db实例,我终于得到了解决方案。在 tearDown()中添加 db.get_engine(self.app).dispose(),使其看起来像:

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


I can't seem to get my Flask app to close or reuse DB connections. I'm using PostgreSQL 9.1.3 and

Flask==0.8
Flask-SQLAlchemy==0.16
psycopg2==2.4.5

As my test suite runs the number of open connections climbs until it hits 20 (the max_connections setting in postgresql.conf), then I see:

OperationalError: (OperationalError) FATAL:  sorry, too many clients already
 None None

I've reduced the code to the point where it's just calling create_all and drop_all (but not issuing any sql as there are no models).

I see connections being checked in and out in the logs:

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

For each test run the address of the connection (the "connection object at xyz" part) is different. I suspect this has something to do with the problem, but I'm not sure how to investigate further.

The code below reproduces the problem in a new venv:

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from unittest import TestCase

import logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger('sqlalchemy.pool').setLevel(logging.DEBUG)
logging.getLogger('sqlalchemy.engine').setLevel(logging.DEBUG)
logging.getLogger('sqlalchemy.dialects').setLevel(logging.DEBUG)
logging.getLogger('sqlalchemy.orm').setLevel(logging.DEBUG)


db = SQLAlchemy()

def create_app(config=None):
    app = Flask(__name__)
    app.config.from_object(config)
    db.init_app(app)
    return app


class AppTestCase(TestCase):
    SQLALCHEMY_DATABASE_URI = "postgresql://localhost/cx_test"
    TESTING = True

    def create_app(self):
        return create_app(self)

    def setUp(self):
        self.app = self.create_app()
        self.client = self.app.test_client()
        self._ctx = self.app.test_request_context()
        self._ctx.push()
        db.create_all()

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


class TestModel(AppTestCase):
    def impl(self):
        logging.warn("impl")
        pass

    def test_01(self):
        self.impl()

    def test_02(self):
        self.impl()

    def test_03(self):
        self.impl()

    def test_04(self):
        self.impl()

    def test_05(self):
        self.impl()

    def test_06(self):
        self.impl()

    def test_07(self):
        self.impl()

    def test_08(self):
        self.impl()

    def test_09(self):
        self.impl()

    def test_10(self):
        self.impl()

    def test_11(self):
        self.impl()

    def test_12(self):
        self.impl()

    def test_13(self):
        self.impl()

    def test_14(self):
        self.impl()

    def test_15(self):
        self.impl()

    def test_16(self):
        self.impl()

    def test_17(self):
        self.impl()

    def test_18(self):
        self.impl()

    def test_19(self):
        self.impl()



if __name__ == "__main__":
    import unittest
    unittest.main()

This is the first time I've used app factories in flask, and I copied this code partly from the Flask-SQLAlchemy docs. Elseware those docs mention that using a db in the wrong context will cause connections to leak - maybe I am doing the init incorrectly?

解决方案

After reading the SQLAlchemy docs and some fiddling with the db instance, I finally got the solution. Add db.get_engine(self.app).dispose() in tearDown() so that it looks like:

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

这篇关于如何使Flask SQLAlchemy重用数据库连接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆