解决sqlalchemy连接mysql查询数据库报:MySQL server has gone away (ConnectionResetError(104, ‘Connection reset...

一:前提

首先需要明确Sqlalchemy会话、mysql连接、SQLAlchemy连接池的概念:

  • 会话(Session):不是一个实际的数据库连接,而是一个持久化操作的工作单元。它保持了一个事务内所有对象的状态,并且在事务结束时,会话负责将这些状态与数据库同步。
  • 连接(Connection):这是一个实际的连接到数据库服务器的通道。
    使用Sqlalchemy进行数据库操作,首先需要创建session会话,才能建立数据库连接,最后才能操作数据库。
  • 连接池:在使用SQLAlchemy这类ORM时,连接是由连接池管理的。
    会话在被创建时,并不立即打开一个新的物理数据库连接。实际的数据库连接是在需要执行数据库操作时才由 SQLAlchemy 池管理系统(如果启用了连接池)动态分配的。
    当创建一个会话并开始一个事务时,SQLAlchemy 按需请求一个连接。如果会话中没有执行任何操作,它可能根本不需要请求一个实际的数据库连接。当会话关闭时,会话内部的所有数据库连接都会被释放回连接池(如果使用的是连接池),并且会话状态被清除。

总结:
连接数据库做一定操作:首先需要sqlalchemy创建会话,然后会话向连接池请求一个mysql连接(连接池用来管理各个连接),从而完成数据库操作。

二:回归该错误

现在很明确 错误是因为Sqlalchemy会话失去了Mysql连接(因为连接超时导致连接失效)导致的。

三:解决办法1

修改连接的超时时间,然后修改一个更大的值:

  1. 登录到MySQL服务器,检查wait_timeout和interactive_timeout的值。
    可以通过执行以下SQL命令查看这些值:

    SHOW VARIABLES LIKE 'wait_timeout';
    SHOW VARIABLES LIKE 'interactive_timeout';
    
  2. 修改参数

    临时修改方式:

    SET @@global.wait_timeout = 28800;  -- 设置为8小时
    SET @@global.interactive_timeout = 28800;  -- 设置为8小时
    

    永久修改方式:

    1. 编辑配置文件:
      打开 MySQL 的配置文件 my.cnf 或 my.ini。您可能需要 root 权限或管理员权限来编辑此文件。
      sudo vi /etc/mysql/my.cnf
    2. 添加或修改这些行:
      在 [mysqld] 部分中添加或修改以下行(单位s):
    wait_timeout = 28800
    interactive_timeout = 28800
    

    这里设置的 wait_timeout 和 interactive_timeout 为 28800 秒,即 8 小时。

    1. 保存并关闭文件:
      保存文件并退出编辑器。
      重启 MySQL 服务:
    sudo systemctl restart mysql
    

四:解决办法2(推荐)

  1. 使用 SQLAlchemy 的 pool_pre_ping来解决:
    SQLAlchemy 1.2及以上版本引入了pool_pre_ping,它可以在从连接池中获取连接并使用它之前自动检查连接的有效性如果连接无效,它会自动尝试重新获取一个新的连接。这是通过发送一个简单的SELECT 1语句到数据库来实现的。如果此操作失败,该连接将被丢弃并替换为一个新的连接。

  2. 使用该方式的原因:
    因为即使调整了超时时间,如果服务的未调用时间超过了新的设置时间,依然有可能遇到连接失效的问题。并且很重要的一点是,sqlalchemy连接池并不能知道一个连接是否已经连接超时失效了。

  3. 问题解决
    在创建引擎是加入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

以上就是本问题的最终解决方案了。

【文章编写不易,如需转发请联系作者!】

  • 24
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值