aiomysql.executemany() 不支持真正异步批量执行,应改用多值 insert 拼接、where in 参数化或事务包裹批量操作,并注意分批、防注入和显式提交。

aiomysql.executemany() 不能直接用,得换思路
直接调用 executemany() 在 aiomysql 中会报错或静默失败,因为它底层不支持真正的异步批量执行——实际是循环调用 execute(),失去并发优势,还可能触发连接超时。真正高效的方式是拼接单条多值 INSERT 或用事务包住多个语句。
INSERT 多值拼接:性能提升最直接的写法
对插入场景,把多条记录合并成一条 SQL 是最快路径,避免网络往返和解析开销。注意控制单条 SQL 长度,防止超过 max_allowed_packet(MySQL 默认 4MB)。
- 用
VALUES %s占位符 +cursor.execute()传入元组列表,aiomysql 会自动展开为VALUES (..), (..), (..) - 每批建议不超过 500–1000 行,具体看字段数和平均长度;可通过
len(str(sql))粗略预估长度 - 不要手拼 SQL 字符串,否则有注入风险;必须依赖参数化方式
sql = "INSERT INTO users (name, email) VALUES %s"
await cursor.execute(sql, [("Alice", "a@x.com"), ("Bob", "b@x.com")])
UPDATE/DELETE 批量操作:靠 WHERE IN + 参数化安全兜底
UPDATE 和 DELETE 没有原生多值语法,只能靠 WHERE id IN (%s, %s, %s) 实现批量。难点在于动态生成占位符数量,且不能超过 MySQL 的 max_allowed_packet 和 max_connections 限制。
- 用
",".join(["%s"] * len(ids))动态构造 IN 子句部分 - 确保
ids是扁平 list/tuple,不能嵌套;传参时直接传整个 list,不要解包 - 若 ID 数量超 10k,分批提交,否则 MySQL 可能拒绝执行或锁表太久
ids = [1, 2, 3, 4]
placeholders = ",".join(["%s"] * len(ids))
sql = f"UPDATE users SET status='done' WHERE id IN ({placeholders})"
await cursor.execute(sql, ids)
事务 + 批量混合操作:别忘了 await conn.commit()
跨语句批量更新(比如先 INSERT 再 UPDATE 关联表)必须显式开启事务,否则每条语句自动提交,失去原子性和性能。aiomysql 不会自动管理事务生命周期。
- 用
async with conn.cursor() as cursor:确保 cursor 正确释放 -
conn.begin()必须显式调用,不能只靠START TRANSACTION字符串 - 出错时要
await conn.rollback(),否则连接可能卡在未结束事务状态 - 批量越大,事务持有时间越长,注意设置合理
innodb_lock_wait_timeout
复杂批量逻辑里最容易漏掉 await conn.commit(),结果数据看似执行了,其实全在事务里没落盘。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











