一:前提
首先需要明确Sqlalchemy会话、mysql连接、SQLAlchemy连接池的概念:
- 会话(Session):不是一个实际的数据库连接,而是一个持久化操作的工作单元。它保持了一个事务内所有对象的状态,并且在事务结束时,会话负责将这些状态与数据库同步。
- 连接(Connection):这是一个实际的连接到数据库服务器的通道。
使用Sqlalchemy进行数据库操作,首先需要创建session会话,才能建立数据库连接,最后才能操作数据库。 - 连接池:在使用SQLAlchemy这类ORM时,连接是由连接池管理的。
会话在被创建时,并不立即打开一个新的物理数据库连接。实际的数据库连接是在需要执行数据库操作时才由 SQLAlchemy 池管理系统(如果启用了连接池)动态分配的。
当创建一个会话并开始一个事务时,SQLAlchemy 按需请求一个连接。如果会话中没有执行任何操作,它可能根本不需要请求一个实际的数据库连接。当会话关闭时,会话内部的所有数据库连接都会被释放回连接池(如果使用的是连接池),并且会话状态被清除。
总结:
连接数据库做一定操作:首先需要sqlalchemy创建会话,然后会话向连接池请求一个mysql连接(连接池用来管理各个连接),从而完成数据库操作。
二:回归该错误
现在很明确 错误是因为Sqlalchemy会话失去了Mysql连接(因为连接超时导致连接失效)导致的。
三:解决办法1
修改连接的超时时间,然后修改一个更大的值:
-
登录到MySQL服务器,检查wait_timeout和interactive_timeout的值。
可以通过执行以下SQL命令查看这些值:SHOW VARIABLES LIKE 'wait_timeout'; SHOW VARIABLES LIKE 'interactive_timeout';
-
修改参数
临时修改方式:
SET @@global.wait_timeout = 28800; -- 设置为8小时 SET @@global.interactive_timeout = 28800; -- 设置为8小时
永久修改方式:
- 编辑配置文件:
打开 MySQL 的配置文件 my.cnf 或 my.ini。您可能需要 root 权限或管理员权限来编辑此文件。
sudo vi /etc/mysql/my.cnf - 添加或修改这些行:
在 [mysqld] 部分中添加或修改以下行(单位s):
wait_timeout = 28800 interactive_timeout = 28800
这里设置的 wait_timeout 和 interactive_timeout 为 28800 秒,即 8 小时。
- 保存并关闭文件:
保存文件并退出编辑器。
重启 MySQL 服务:
sudo systemctl restart mysql
- 编辑配置文件:
四:解决办法2(推荐)
-
使用 SQLAlchemy 的 pool_pre_ping来解决:
SQLAlchemy 1.2及以上版本引入了pool_pre_ping,它可以在从连接池中获取连接并使用它之前自动检查连接的有效性。如果连接无效,它会自动尝试重新获取一个新的连接。这是通过发送一个简单的SELECT 1语句到数据库来实现的。如果此操作失败,该连接将被丢弃并替换为一个新的连接。 -
使用该方式的原因:
因为即使调整了超时时间,如果服务的未调用时间超过了新的设置时间,依然有可能遇到连接失效的问题。并且很重要的一点是,sqlalchemy连接池并不能知道一个连接是否已经连接超时失效了。 -
问题解决
在创建引擎是加入pool_pre_ping的设置:
def set_engine():
mysql_host = get_params_by_env_or_config('MYSQL_HOST')
mysql_port = get_params_by_env_or_config('MYSQL_PORT')
mysql_username = get_params_by_env_or_config('MYSQL_USERNAME')
mysql_password = get_params_by_env_or_config('MYSQL_PASSWORD')
mysql_db = get_params_by_env_or_config('MYSQL_DB')
db_uri = f'mysql+pymysql://{mysql_username}:{mysql_password}@{mysql_host}:{mysql_port}/{mysql_db}?charset=utf8mb4'
engine = create_engine(
db_uri,
echo=get_params_by_env_or_config("SQLALCHEMY_ECHO"),
# 添加以下两项配置
pool_pre_ping=True, # 启用预检查
pool_recycle=3600
)
return engine
以上就是本问题的最终解决方案了。
【文章编写不易,如需转发请联系作者!】