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

