Python3.6+SQLAlchemy连接MySQL报错:MySQL Connection not available
我之前也碰到过一模一样的情况——Python脚本用SQLAlchemy连MySQL,跑几个小时没碰数据库,再操作就炸出sqlalchemy.exc.OperationalError: (mysql.connector.errors.OperationalError) MySQL Connection not available这个错误,哪怕已经把pool_recycle设到290秒也没用。下面说几个我亲测有效的解决思路:
1. 确认MySQL的超时参数配置
首先得搞清楚你的MySQL服务器端的wait_timeout和interactive_timeout参数值,pool_recycle必须小于这两个参数里的最小值才算有效。比如如果MySQL的wait_timeout实际是200秒,那你设的290秒就没意义——数据库早把连接回收了,SQLAlchemy还在拿旧连接用。
你可以登录MySQL执行这条命令查参数:
SHOW VARIABLES LIKE '%timeout';
如果发现服务器端的超时值比pool_recycle小,要么修改MySQL配置文件(my.cnf/my.ini)调整参数后重启服务,要么把pool_recycle再调低,比如设成180秒。
2. 开启连接池的连接验证
有时候光靠pool_recycle还不够,比如网络波动或者MySQL提前回收连接,SQLAlchemy的连接池可能没检测到。这时候可以开启连接预检测,每次从池里拿连接前先确认它还能用。
创建引擎时加上pool_pre_ping=True参数:
from sqlalchemy import create_engine engine = create_engine( 'mysql+mysqlconnector://user:password@host/dbname', pool_recycle=290, pool_pre_ping=True )
这个参数会自动在获取连接前执行SELECT 1测试,如果连接失效,就会丢弃旧连接并创建新的,从根源上避免用失效连接的问题。
3. 避免长期持有连接
如果你的脚本里有长期占用连接的情况(比如把会话实例存在全局变量里、打开会话后一直不关闭),那pool_recycle也起不到作用——因为连接一直被占用,连接池没法回收它。
一定要确保每次数据库操作后及时释放连接,推荐用上下文管理器自动管理会话:
from sqlalchemy.orm import sessionmaker Session = sessionmaker(bind=engine) # 用with语句自动关闭会话,连接用完自动回池 with Session() as session: result = session.query(MyModel).all()
别把Session做成全局对象或者长时间持有不释放,否则连接会被死死占住。
4. 微调连接池其他参数
如果脚本并发不高,可以试试调小pool_size(默认是5),或者设置pool_timeout(获取连接超时时间),避免池里堆积太多闲置连接。比如:
engine = create_engine( 'mysql+mysqlconnector://user:password@host/dbname', pool_recycle=290, pool_pre_ping=True, pool_size=3, pool_timeout=10 )
总结下来,pool_pre_ping=True + 确保pool_recycle小于MySQL超时参数是最有效的组合,基本能解决90%以上的闲置连接失效问题。
内容的提问来源于stack exchange,提问作者Nyxynyx

