必须await aiomysql.connect()等所有异步方法,否则协程同步执行阻塞事件循环;必须用aiomysql.create_pool()创建连接池并在startup时初始化,避免每次请求新建连接导致连接耗尽或超时。

直接用 aiomysql.connect() 每次新建连接、不复用、不 await,就等于在协程里塞同步操作——事件循环立刻卡死,所有并发请求排队等你那一个查询返回。
为什么 aiomysql 不 await 就会阻塞 FastAPI
aiomysql 的核心是基于 asyncio 的非阻塞 I/O,但它的所有关键方法(如 connect()、execute()、fetchall())都必须显式 await。漏掉任何一个 await,Python 就不会挂起当前协程,而是同步执行,把事件循环拖进阻塞状态。
常见错误现象:
- 接口响应时间忽高忽低,P95 延迟飙升到 200ms+,而数据库本身耗时不到 10ms
- 并发压测时 QPS 上不去,CPU 利用率却很低(说明大量时间花在空等 I/O)
- 日志里反复出现
Task was destroyed but it is pending!—— 这是事件循环被卡住后强行清理未完成协程的信号
必须用连接池,不能每次 connect()
aiomysql.create_pool() 是唯一安全的初始化方式。手动调 aiomysql.connect() 一次只建一个连接,没有复用、没有超时控制、无法限制最大连接数,高并发下极易触发 MySQL 的 Too many connections 错误。
实操建议:
- 连接池需在应用启动时创建(
@app.on_event("startup")),全局复用,不能在每个路由函数里重复创建 - 务必设置
minsize和maxsize,例如minsize=2, maxsize=20,避免冷启动慢或连接爆炸 - 连接池对象应存为全局变量或通过依赖注入传递,不要在每次请求中重新 acquire
- 使用
async with pool.acquire() as conn:确保连接自动归还,否则连接泄漏会迅速耗尽池子
SQLAlchemy 2.0 + aiomysql 组合要注意什么
SQLAlchemy 2.0 原生支持异步,但底层仍需适配驱动。若你用 create_async_engine("mysql+aiomysql://..."),注意两点:
- URL 中必须用
mysql+aiomysql,不是mysql+pymysql或mysql://,否则会静默退化为同步模式 -
session.execute()返回的是Result对象,但scalars()、fetchone()、fetchall()全部是协程方法,必须await - 别混用同步 ORM 操作:比如在
async def路由里调session.commit()(这是同步方法),要换成await session.commit() - 事务必须显式
await session.begin()启动,且整个事务块要在同一个async with session.begin():内完成
容易被忽略的错误点:异常处理与超时控制
aiomysql 默认不设查询超时,一个慢查询可能让整个连接池卡住。必须主动加 asyncio.wait_for() 或利用连接池的 connect_timeout 和 echo 参数辅助诊断。
关键细节:
-
pool.acquire()本身支持timeout参数,例如async with pool.acquire(timeout=3) as conn:,超时抛asyncio.TimeoutError - 数据库连接层的
connect_timeout控制握手时间,read_timeout/write_timeout控制后续通信,三者要分清作用域 - 捕获
aiomysql.MySQLError时,注意它不继承Exception的全部行为,某些日志框架可能漏打堆栈 - 别在
finally块里手动conn.close()—— 连接池管理的连接 close 后无法重用,应靠async with自动释放
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











