Недавно моя программа Flask обнаружила ошибку Lost connection to MySQL server during query. Я искал некоторые документы и обсуждения. Кажется, что MySQL отключил соединение, но flask не перезапустил эти соединения с истекшим сроком действия.
Сейчас я использую Flask_SQLAlchemy==2.4.4. Из документации flask 2.x я узнал, что настройка SQLALCHEMY_POOL_RECYCLE может регулировать время для flask для повторного использования просроченных соединений. Я попробовал его установить, но мою проблему это не решило.
Это моя демонстрация:
import time
import sqlalchemy as sql
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class TestData(db.Model):
id = sql.Column(sql.BigInteger, primary_key=True)
def create_app() -> Flask:
app: Flask = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://mysql_host"
app.config["SQLALCHEMY_POOL_SIZE"] = 1
app.config["SQLALCHEMY_POOL_RECYCLE"] = 3
db.init_app(app)
return app
def test():
app = create_app()
with app.app_context():
q1 = TestData.query.get(0)
print(q1)
time.sleep(10)
q2 = TestData.query.get(1)
print(q2)
test()
Я запустил SET GLOBAL wait_timeout = 8;, чтобы установить время отключения MySQL на 8 с, а также настроил app.config["SQLALCHEMY_POOL_RECYCLE"] = 3. После time.sleep(10) запрос q2 по-прежнему не удался.
версия пакета
SQLAlchemy==1.3.22
Flask_SQLAlchemy==2.4.4
Flask==1.1.2






Из документации по Setting Pool Recycle:
Обратите внимание, что аннулирование происходит только во время извлечения, а не для каких-либо соединений, которые находятся в извлеченном состоянии.
Ваш первый .get() проверяет соединение, начинает транзакцию и выдает запрос SELECT. Поскольку вы не завершаете транзакцию, соединение остается «открытым» (удерживается в извлеченном состоянии), и через 10 секунд бездействия вы пытаетесь использовать то же самое соединение снова.
Исправление состоит в том, чтобы завершить транзакцию после первого .get(), чтобы соединение вернулось в пул. Через 10 секунд ваш следующий .get() проверит соединение и оно будет перезапущено.
q1 = TestData.query.get(0)
print(q1)
db.session.rollback() # complete the transaction
time.sleep(10)
q2 = TestData.query.get(1)
print(q2)