Flask+SQLAlchemy删除MySQL记录请求倍增引发QueuePool溢出问题
问题根因
你遇到的问题由前后端两个错误共同导致:
- 前端事件重复绑定:每次datatables表格重绘(比如删除后刷新列表)时,都重复给删除按钮注册了点击事件回调,没有解绑旧事件,导致点击一次按钮触发N次删除请求,N等于历史删除次数+1,对应你日志里每次删除的请求数线性递增的表现。
- 后端数据库连接泄漏:原生SQLAlchemy的session管理逻辑错误,手动调用close、remove的时机不对,加上你之前用Flask-SQLAlchemy的方式不正确,导致数据库连接没有正常释放,请求量上来后直接打满连接池,抛出QueuePool超限错误。
可行解决方案
第一步:修复前端事件绑定问题(必须先修,否则请求数还是会递增)
优先用事件委托的方式绑定点击事件,只需要页面初始化时绑定一次,不需要每次表格重绘重复绑定:
// 页面初始化时仅执行一次,不要放到datatables的drawCallback回调内 $(document).on('click', '.你的删除按钮类名', function() { const blogId = $(this).data('你存博客id的自定义属性名') // 原有删除请求逻辑 $.post(`/backend/blog/delete/${blogId}`, function(res) { if (res.status) { // 成功后刷新datatables } }) })
如果必须把绑定逻辑放到drawCallback里,每次绑定前先解绑旧事件:
function drawCallback() { $('.你的删除按钮类名').off('click').on('click', function() { // 原有删除逻辑 }) }
第二步:修复后端session管理问题,推荐直接用标准Flask-SQLAlchemy用法:
1. 修正入口文件__init__.py配置
import os from flask import Flask from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() def create_app(): app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('SQLALCHEMY_DATABASE_URI') app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # 连接池配置可按需调整 app.config['SQLALCHEMY_POOL_SIZE'] = 10 app.config['SQLALCHEMY_MAX_OVERFLOW'] = 20 db.init_app(app) # 注册你的蓝图 from .你的蓝图模块名 import blueprint app.register_blueprint(blueprint, url_prefix='/backend/blog') # 初始化表结构要在app上下文内执行 with app.app_context(): db.create_all() return app
2. 修正Blog模型代码
from datetime import datetime from 你的项目入口模块名 import db # 注意User模型也要同步改为继承db.Model class Blog(db.Model): __tablename__ = 'blog' id = db.Column(db.Integer(), primary_key=True) author_id = db.Column(db.String(255), nullable=False) title = db.Column(db.String(255), nullable=False, unique=True) content = db.Column(db.String(255), nullable=False) # 注意:default传函数引用不要加括号,否则时间只会在模块加载时计算一次 created_at = db.Column(db.DateTime(), default=datetime.now) updated_at = db.Column(db.DateTime(), default=datetime.now, onupdate=datetime.now) def collect_data_serverside(self, request): DATA = [] # 原有sessionDB替换为db.session query = db.session.query(User, Blog).filter(User.id==Blog.author_id) for u, b in query.all(): DATA.append({'A': b.id, 'B': u.nombre, 'C': b.title, 'D': b.created_at}) columns = table_schemas.BLOG return ServerSideTable(request, DATA, columns, True, True, 'backend.blog', 'C', 'table_blogposts').output_result() @staticmethod def delete(id): db.session.query(Blog).filter(Blog.id == id).delete() db.session.commit() # 不需要手动调用close/remove,Flask-SQLAlchemy会自动在请求结束后回收连接
额外说明
如果不想改用Flask-SQLAlchemy,要继续用原生SQLAlchemy的话,只需要做两个修改:
- 在蓝图中绑定请求结束钩子,统一回收session:
@blueprint.teardown_request def remove_session(exception=None): sessionDB.remove()
- 删除Blog.delete方法里的
sessionDB.close()和sessionDB.remove()两行,不要手动处理session回收。
内容的提问来源于stack exchange,提问作者Berkeley Now
相关产品推荐
相关产品推荐

