DEBUG.WIKI
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
OnlineSIM:在线接收短信,虚拟号码租用
野草云;香港 200Mbps 峰值;不限月流量 · BGP VPS;查看套餐 →

SQLAlchemy 第二次取 aiomysql 连接,报 ping 缺少 reconnect 参数

SQLAlchemy 首次查询成功、第二次取连接报 ping 缺参,核对 PyMySQL 1.2.0 与旧异步方言组合,使用修复版本复验连接池。

第一次 engine.connect() 能执行查询,连接归还后再取一次,却在发出业务 SQL 之前失败:

TypeError: AsyncAdapt_aiomysql_connection.ping() missing 1 required positional argument: 'reconnect'

如果开启了 pool_pre_ping=True,并且堆栈经过 SQLAlchemy 的 MySQL 方言 do_ping(),先核对 SQLAlchemy 与 PyMySQL 的组合。这不等于 MySQL 密码错误,也不应靠增加连接池容量处理。

这一兼容问题明确涉及 SQLAlchemy 2.0.48、2.0.49 与 PyMySQL 1.2.0,aiomysql 0.2.0 和 0.3.2 都有相关记录;asyncmy 方言也受过影响。SQLAlchemy 2.0.50 的正式变更包含修复。不要被某些版本输出中的 2.2.8 误导,定位时以发行包版本为准。

为什么第一条查询正常

新建连接第一次交出时,一般无需对它预先 ping;连接回到池中后,后续取用才会进入预检查。因此连续两次“取出、使用、归还”,比在同一个连接里执行两条 SQL 更能暴露这个问题。

旧方言会根据 PyMySQL 的 ping() 签名判断是否需要显式传 False。PyMySQL 1.2.0 改变了相关默认行为,旧适配代码随后可能无参数调用异步适配器,而适配器仍要求 reconnect 参数。修复还要分别考虑 aiomysql 和 asyncmy 自身的连接签名,不能只给一个函数补默认值就认为所有组合都处理好了。

在发生错误的服务环境里读取发行信息:

python -m pip show SQLAlchemy aiomysql asyncmy PyMySQL
python -m pip check

未安装的驱动可忽略。实际应用使用哪个方言,由连接 URL 中的 mysql+aiomysql 或 mysql+asyncmy 等前缀决定,不是由“环境里装了哪几个包”决定。

使用包含修复的 SQLAlchemy,再复验两次取连接

按项目兼容范围选择包含修复的正式版本;2.0 分支可核对到的修复版本是 2.0.50,更高版本不必为此退回。保存依赖锁文件差异,让包管理器解析匹配的驱动组合,不手改适配器私有实现。

下面的诊断示例需要一个已授权、可连接的测试 MySQL 数据库。DATABASE_URL 由环境变量提供,避免把密码写入脚本或日志。查询只读取常量:

import asyncio
import os
from sqlalchemy import text
from sqlalchemy.ext.asyncio import create_async_engine

async def check_pool():
    engine = create_async_engine(
        os.environ["DATABASE_URL"],
        pool_pre_ping=True,
        pool_size=1,
        max_overflow=0,
    )
    try:
        for number in (1, 2):
            async with engine.connect() as conn:
                value = await conn.scalar(text("SELECT 1"))
                print(number, value)
    finally:
        await engine.dispose()

if __name__ == "__main__":
    asyncio.run(check_pool())

测试 URL 的前缀要与业务方言一致。这里让两次取用共享同一个小池、在同一个事件循环中完成,且每轮都退出连接上下文。预期两轮都得到 1,第二轮不再出现缺参错误;它不验证数据库重启或事务中途断线时的恢复。

关闭预检查只能改变触发条件

临时设置 pool_pre_ping=False 可能绕过这次 ping,但会同时放弃取连接时的存活检查,旧连接之后可能在业务查询中失败。若业务需要应对长时间空闲、网络切换或数据库重启,应优先修复依赖组合并保留预检查。

预检查本身也不能恢复已经执行到一半的事务。修复后仍有连接异常时,要把缺参 TypeError、真实断线和事务重试分开记录,避免将所有失败都归到同一个版本兼容问题。