最近有个问题困扰着我,php请求我flask接口,增加网站而页面提示增加成功,实际并未添加进去,产品反应这个问题时这个问题居然无法复现!!
最后把流程梳理了一遍,看看请求过来的数据到哪里中断,最后发现是数据库连接池的问题
还原问题
打开sqlalchemy 运行日志,echo=True,插入一个测试网站,该网站没有添加,并报错
问题分析
提示数据库连接超时,所以考虑数据库连接问题,但不知道问题最主要原因是什么,猜测可能是即某个mysql长连接很久没有新的请求发起,达到了server端的timeout,被server强行关闭。
此后再通过这个connection发起查询的时候,就会报错server has gone away,导致查询结束,后续也就没有数据插入
问题原理
连接池连接mysql数据库失败,连接超时,mysql配置文件存在两个参数,是负责管理连接超时的。
- interactive_timeout:针对交互式连接 默认28800秒 即8个小时
- wait_timeout: 针对非交互式连接 默认28800秒 即8个小时
我们做项目一般使用数据库连接池来获取连接,连接池里的连接可能会较长时间不关闭,等待被使用,这就与mysql连接超时机制起冲突了,当连接池配置永不关闭或者关闭时间超过8小时就会出现这个问题
当超过8个小时没有新的数据库请求的时候,数据库连接就会断开,如果我们连接池的配置是用不关闭或者关闭时间超过8小时,这个时候连接池没有回收并且还认为连接池与数据库之间的连接还存在,就会继续连接,但是数据库连接断开了,就会报错数据库连接失败
项目一般使用数据库连接池来获取连接,连接池里的连接可能会较长时间不关闭,等待被使用,这就与mysql连接超时机制起冲突了,当连接池配置永不关闭或者关闭时间超过8小时就会出现我所遇到的问题。
当超过8个小时没有新的数据库请求的时候,比如夜间到早晨,数据库连接就会断开,如果我们连接池的配置是用不关闭或者关闭时间超过8小时,这个时候连接池没有回收并且还认为连接池与数据库之间的连接还存在,就会继续连接,但是数据库连接断开了,就会提示数据库连接失败
问题解决
在代码中
from sqlalchemy.orm import scoped_session
engine = create_engine(
"mysql+pymysql://root:mysql@127.0.0.1:3306/test?charset=utf8",
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的时间,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
SessionFactory = sessionmaker(bind=engine)
session = scoped_session(SessionFactory)
pool_recycle 就是设置与数据库连接回收的,值为-1即永不回收,设置可设置3600秒,只要这个值小于数据库最大超时时间,就不会出现数据库连接超时的错误了