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

Flask应用并发读取MySQL数据库时出现阻塞及连接丢失问题求助

Flask+MySQL并发访问问题解决方案

问题描述

我有个Flask程序,在/路由的GET方法里用Python访问MySQL数据库,代码如下:

""" 返回当前用户的现金 """
def returncash(argdb):
    argdb.execute("SELECT cash FROM fin_users WHERE id = %s", (session['user_id'],))
    row = argdb.fetchall()

    return row[0]['cash']

这段代码大部分时候正常,但快速刷新两次页面程序就会挂起,问题出在argdb.execute那一行。看起来像是同时访问同一条记录导致冻结,没有错误提示,就是卡着不往下执行。多刷几次会出现IndexError: bytearray index out of range错误。

我试着加表锁解决,改成这样:

""" 返回当前用户的现金 """
def returncash(argdb):
    argdb.execute("LOCK TABLES fin_users READ")
    argdb.execute("SELECT cash FROM fin_users WHERE id = %s", (session['user_id'],))
    row = argdb.fetchall()
    argdb.execute("UNLOCK TABLES")

    return row[0]['cash']

结果又出现新的IndexError错误。

--- 编辑 ---

按照建议执行python -m pip install mysql-connector-python更新了驱动,更新成功后快速刷新页面,程序不再冻结,但立刻报Lost connection to MySQL server during query错误,打算换个数据库驱动试试。

问题根源

核心问题是数据库连接/游标被多请求共享,导致并发访问时数据混乱。Flask默认是多线程的,每个请求在不同线程里执行,如果你的db对象是全局共享的,多个线程同时用同一个游标执行查询,就会出现数据包解析错误、连接丢失这类问题。

解决步骤

1. 确保每个请求使用独立的数据库连接/游标

不要在全局初始化一个连接或游标,而是在每个请求里创建新的连接,或者使用连接池。可以用Flask的请求钩子来管理连接:

from flask import Flask, g
import mysql.connector

app = Flask(__name__)

def get_db():
    if 'db' not in g:
        g.db = mysql.connector.connect(
            host='localhost',
            user='your_user',
            password='your_password',
            database='your_db'
        )
    return g.db

@app.teardown_appcontext
def close_db(error):
    if 'db' in g:
        g.db.close()

@app.route('/')
def index():
    db = get_db()
    cursor = db.cursor(dictionary=True)  # 用字典游标方便按字段名取值
    cursor.execute("SELECT cash FROM fin_users WHERE id = %s", (session['user_id'],))
    row = cursor.fetchone()
    cursor.close()
    return str(row['cash']) if row else "无数据"

这样每个请求都会拿到独立的连接,避免多线程共享导致的冲突。

2. 替换数据库驱动(推荐)

mysql-connector-python偶尔会有这类并发问题,换成更成熟的pymysql试试:

  • 安装:pip install pymysql
  • 使用方式和mysql.connector类似,只需要改导入和连接部分:
import pymysql

def get_db():
    if 'db' not in g:
        g.db = pymysql.connect(
            host='localhost',
            user='your_user',
            password='your_password',
            database='your_db',
            cursorclass=pymysql.cursors.DictCursor  # 字典游标
        )
    return g.db

pymysql在并发场景下稳定性更好,这类数据包错误出现的概率低很多。

3. 不要手动加表锁

你之前加的表锁完全没必要,MySQL的InnoDB引擎默认支持行级锁,读操作不会阻塞其他读请求。手动加表锁反而会加剧并发问题,导致请求排队甚至死锁。

4. 检查MySQL服务器配置

如果换驱动后还是出现连接丢失,检查MySQL的wait_timeout和interactive_timeout参数,确保不会过早断开空闲连接。可以在my.cnf(或my.ini)里调整:

wait_timeout = 28800
interactive_timeout = 28800

修改后重启MySQL服务。

总结

优先用请求级的独立连接+成熟驱动(pymysql),这是解决这类并发问题最直接的方案。全局共享连接/游标在多线程环境下本来就是错误的用法,一定要避免。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 19:49:50