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

Python+Flask+flask_mysqldb出现Error 2006(Server has gone away)求助

问题分析与解决方案

我一眼就看出问题出在哪了——你混用了两个不同的Flask MySQL扩展,并且连接管理的方式完全错误,这才导致了这个看似不符合超时场景的"Server has gone away"错误。下面给你拆解原因和修复步骤:

核心原因拆解

1. 两个MySQL扩展的冲突

你的主文件里用的是flaskext.mysql(也就是Flask-MySQL),但视图文件usuarios.py里导入的是flask_mysqldb——这是两个完全独立的库,它们的连接生命周期管理逻辑完全不一样。当第一个请求完成后,flask_mysqldb的自动清理钩子会关闭数据库连接,但主文件的配置是给另一个扩展用的,两者的连接管理完全脱节,第二次请求时就会尝试使用已经被关闭的连接,直接触发2006错误。

2. 每次请求创建新MySQL实例的错误操作

在list_all函数里,你每次都调用mysql = MySQL(current_app)创建新的MySQL实例,这会导致每个请求都新建一个数据库连接,而不是复用连接池。请求结束后连接被关闭,但后续请求因为扩展冲突的问题,无法正确重建连接,自然就报错了。

3. Gunicorn同步Worker的影响

你用了gunicorn -w 1(单个同步Worker),这个Worker处理完第一个请求后,连接已经被清理关闭,第二个请求过来时,Worker尝试重新获取连接,但因为扩展混用的问题,无法正确初始化新连接,所以报错。当你增加Worker数量,每个Worker可以处理一次请求(处理后连接被关闭),所以能多执行几次,直到所有Worker都处理过一次请求,再请求就会遇到同样的问题。


具体修复步骤

第一步:统一使用flask_mysqldb扩展

先卸载没用的flaskext.mysql(如果没其他地方用到的话),然后整个项目统一用flask_mysqldb:

修改主文件main.py:

import os
from flask import Flask, render_template
from flask_mysqldb import MySQL  # 改成flask_mysqldb
import endpoints.usuario as usuario

app = Flask(__name__, static_folder='/root/sftp/atom-projects/flask-example/public/')
# 配置项保持不变
app.config['MYSQL_HOST'] = '123'
app.config['MYSQL_USER'] = '123'
app.config['MYSQL_PASSWORD'] = '123'
app.config['MYSQL_DB'] = '123'

# 初始化MySQL实例并绑定到app,这一步很重要!
mysql = MySQL(app)

app.add_url_rule('/usuarios', 'usuarios', usuario.list_all, methods=['GET'])

@app.errorhandler(404)
def not_found(e):
    return app.send_static_file('index.html')

第二步:在视图里复用已初始化的MySQL实例

修改usuarios.py,不要再每次创建新实例,直接导入主文件里已经初始化好的mysql:

from flask import make_response
import bcrypt
# 从主文件导入已初始化的mysql实例
from main import mysql

def list_all():
    cursor = mysql.connection.cursor()
    cursor.execute("select * from usuario")
    records = cursor.fetchall()
    usuarios = []
    for row in records:
        usuarios.append({"id":row[0], "nome":row[1], "email":row[2], "senha":row[3], "tipo":row[4]})
    
    # 这里可以优化:用IN语句批量查询,减少循环查库的次数
    for usuario in usuarios:
        cursor.execute("select * from tipo_usuario where id = %s", [usuario['tipo']])
        records = cursor.fetchall()
        for row in records:
            usuario['tipo'] = {"id":row[0], "permissao":row[1]}
    
    # 好习惯:用完游标记得关闭
    cursor.close()
    return make_response({"msg":'', "error":False, "data":usuarios})

第三步:添加自动重连机制(可选但推荐)

为了避免后续可能出现的连接闲置被服务器关闭的问题,可以在主文件里加一个请求前的钩子,自动检查并重连:

@app.before_request
def before_request():
    try:
        mysql.connection.ping(True)  # ping(True)会自动重连失效的连接
    except Exception as e:
        print(f"MySQL重连失败: {e}")
        raise

额外优化建议

  • 批量查询优化:你现在循环每个用户查一次tipo_usuario,可以改成用SELECT * FROM tipo_usuario WHERE id IN (xxx, xxx)批量查询,然后把结果映射到用户数据里,能大幅减少数据库交互次数。
  • 配置连接池:flask_mysqldb支持连接池,你可以在主文件里添加配置:
    app.config['MYSQL_POOL_SIZE'] = 5  # 连接池大小
    app.config['MYSQL_POOL_RECYCLE'] = 3600  # 3600秒回收一次连接,避免被服务器主动关闭
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:17:55