You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask中PostgreSQL连接池为何创建两个空闲连接?

PostgreSQL连接池连接数不符合预期问题

我正在开发一个用于学习的Flask应用,整体运行正常,但PostgreSQL连接池的连接数不符合预期。我使用psycopg2的SimpleConnectionPool,设置minconn=1、maxconn=10,启动时创建了1个连接。通过before_request()从池获取连接,teardown_request()将连接放回池,本应始终只有1个连接,但pgadmin显示有2个空闲连接;将minconn改为2时,启动时会出现4个连接。请问这是什么原因?

相关代码

from flask import current_app, g
from psycopg2.extras import DictCursor
from psycopg2 import pool
import psycopg2

def database_connection(app):
    dsn = f'''postgresql://{current_app.config['SQL_USERNAME']}:{current_app.config['SQL_PASSWORD']}@{current_app.config['SQL_HOST']}:{current_app.config['SQL_PORT']}/{current_app.config['SQL_DATABASE']}'''
    pool = psycopg2.pool.SimpleConnectionPool(minconn = current_app.config['SQL_MINCONN'], maxconn = current_app.config['SQL_MAXCONN'], dsn = dsn)

    @app.before_request
    def open_connection():
        if 'connection' not in g:
            g.connection = pool.getconn()
            g.connection.autocommit = True
            g.cursor = g.connection.cursor(cursor_factory = DictCursor)

    @app.teardown_request
    def close_connection(response):
        g.cursor.close()
        g.connection = g.pop('connection', None)
        if g.connection is not None:
            pool.putconn(g.connection)

        return response

问题原因与解决方案

核心原因

  1. Flask调试模式的重载进程:调试模式下Flask会启动两个进程——主进程和代码变更检测的重载进程,每个进程都会独立初始化自己的连接池。所以minconn=1时两个进程各创建1个连接,最终显示2个;minconn=2时则是2×2=4个连接。
  2. 连接回收逻辑错误:teardown_request中先执行g.pop('connection', None)移除了连接,后续再判断g.connection必然是None,导致连接无法正确放回池,长期运行会引发连接泄漏,进一步加剧连接数异常。

修复步骤

  • 关闭调试重载或调试模式
    开发环境需要调试的话,可关闭重载进程:

    if __name__ == '__main__':
        app.run(debug=True, use_reloader=False)
    

    生产环境直接关闭debug模式即可。

  • 修正连接回收逻辑
    先取出连接再判断,避免无效检查:

    @app.teardown_request
    def close_connection(response):
        if 'cursor' in g:
            g.cursor.close()
        conn = g.pop('connection', None)
        if conn is not None:
            pool.putconn(conn)
        return response
    
  • 确保连接池全局唯一
    将连接池存储在app.config中,避免重复初始化:

    def database_connection(app):
        if 'db_pool' not in app.config:
            dsn = f'''postgresql://{app.config['SQL_USERNAME']}:{app.config['SQL_PASSWORD']}@{app.config['SQL_HOST']}:{app.config['SQL_PORT']}/{app.config['SQL_DATABASE']}'''
            app.config['db_pool'] = psycopg2.pool.SimpleConnectionPool(
                minconn=app.config['SQL_MINCONN'],
                maxconn=app.config['SQL_MAXCONN'],
                dsn=dsn
            )
        pool = app.config['db_pool']
    
        # 后续before_request和teardown_request逻辑不变
    

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 23:41:10