aiomysql真正生效需全栈异步:单改数据库驱动无效,必须配合事件循环并发调度、复用连接池、上游I/O全异步化,并正确await所有协程调用,否则反致性能下降。

用 aiomysql 替代 PyMySQL 或 mysqlclient 确实能提升高并发场景下的 IO 吞吐,但前提是你的整个应用栈是异步的——如果只是把单个数据库调用改成 aiomysql,而主逻辑仍是同步阻塞式,性能反而可能更差。
为什么 asyncio + aiomysql 才真正生效
aiomysql 本身不加速单次查询,它只是把 MySQL 协议封装成 awaitable 对象。真正起作用的是事件循环调度多个 await conn.execute(...) 时复用同一个线程、避免 OS 级线程切换开销。常见误用是:在 async def 里调用了 aiomysql,但上层用 asyncio.run() 包一层就完事——这其实只并发了 1 个请求,和同步没区别。
- 必须确保 Web 框架(如 FastAPI、aiohttp)或任务调度器(如
asyncio.create_task())真正并发发起多个数据库操作 - 连接池
aiomysql.Pool要提前初始化并复用,不能每次请求都await aiomysql.create_pool() - 所有上游 I/O(HTTP 请求、Redis、文件读写)也得是异步的,否则一个同步调用就会卡住整个 event loop
连接池配置的关键参数
aiomysql.create_pool() 的默认参数对生产环境太保守,容易成为瓶颈。比如 minsize=1 和 maxsize=10 在压测时经常看到大量请求等待空闲连接。
-
minsize建议设为 CPU 核数 × 2~4,避免冷启动时频繁建连 -
maxsize不宜盲目调大,超过 50 后 MySQL 服务端可能因并发连接数过多触发max_connections限制,需同步检查 MySQL 配置 - 务必设置
pool_recycle=3600(单位秒),防止长连接被防火墙或中间件静默断开后,aiomysql还往里发查询导致OperationalError: (2013, "Lost connection to MySQL server during query")
常见错误:忘记 await 或混用 sync/async API
最典型的报错是 RuntimeWarning: coroutine 'Pool.acquire' was never awaited,或者直接抛出 TypeError: object XXX can't be used in 'await' expression。根本原因是:把返回 Coroutine 的方法当成了同步函数用。
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
立即学习“Python免费学习笔记(深入)”;
-
pool.acquire()必须await,不是pool.acquire -
conn.execute()、cursor.fetchone()、conn.commit()全部要await - 别在
with await pool.acquire() as conn:里写conn.cursor()——正确写法是async with conn.cursor() as cur: - 如果已有同步代码库,不要试图用
asyncio.to_thread()包裹mysqlclient来“过渡”,延迟更高且失去连接复用优势
实际替换时要注意的兼容性细节
aiomysql 接口尽量兼容 PyMySQL,但仍有几处硬差异,不改会直接报错。
-
cursor.lastrowid是属性,但aiomysql中它是协程,得写成await cursor.lastrowid -
cursor.fetchall()返回list,但aiomysql返回tuple,且字段名不带表别名前缀(如SELECT u.id FROM user u中u.id取出来字段名是id而非u.id) - 事务控制必须显式
await conn.begin(),不能依赖 autocommit=False + execute("BEGIN") - 批量插入用
executemany()时,aiomysql不支持字典列表,只接受元组列表:[(1,"a"), (2,"b")],不能传[{"id":1,"name":"a"}, ...]
真正卡住人的往往不是语法,而是连接泄漏——忘了 async with 或没 properly close() pool;还有就是没意识到 MySQL 自身的 wait_timeout 默认 8 小时,比 pool_recycle 设得大,导致连接池里一堆 stale connection。


















