aiosqlite连接必须用async with管理,不能仅await connect();查询需用fetchall()/fetchone()等异步方法;占位符只支持?;事务需显式commit()。

aiosqlite 连接必须用 async with,不能直接 await connect()
很多人写 await aiosqlite.connect("db.sqlite") 直接报错:TypeError: object Connection can't be used in 'await' expression。这是因为 aiosqlite.connect() 返回的是一个协程对象,不是连接本身;它必须被 await 执行,但更关键的是——连接生命周期必须由 async with 管理。
不这么做会导致连接泄漏、事务卡死、甚至 SQLite 的“database is locked”错误在并发请求下高频出现。
- ✅ 正确写法:
async with aiosqlite.connect("app.db") as db: await db.execute("INSERT INTO logs (msg) VALUES (?)", ("hello",)) await db.commit() - ❌ 错误写法:
conn = await aiosqlite.connect("app.db")(漏掉async with)、conn.close()(同步关闭无效) - ⚠️ 注意:
aiosqlite.connect()默认不启用 WAL 模式,高并发写入时容易阻塞,建议显式开启:async with aiosqlite.connect("app.db") as db: await db.execute("PRAGMA journal_mode = WAL")
执行查询要用 fetchall() / fetchone(),不能直接 for row in cursor
SQLite 的游标对象(aiosqlite.Cursor)不支持异步迭代,写 for row in cursor: 会报 AttributeError 或静默失败——它根本不会进循环。
这是初学者最常卡住的地方:看着文档里有 cursor,就以为和标准库一样能直接遍历。
立即学习“Python免费学习笔记(深入)”;
- ✅ 获取多行:
rows = await cursor.fetchall(),返回list[tuple] - ✅ 获取单行:
row = await cursor.fetchone(),返回tuple或None - ✅ 获取指定数量:
rows = await cursor.fetchmany(10) - ⚠️ 注意:
fetchall()会把全部结果加载进内存,大表慎用;如需流式处理,得手动分页 + LIMIT/OFFSET
参数占位符只能用 ?,不支持命名参数(:name 或 %(name)s)
aiosqlite 底层复用的是 Python 标准库的 sqlite3,但异步封装没实现命名参数解析。写 "SELECT * FROM users WHERE id = :id" 并传入 {"id": 123},会抛出 sqlite3.ProgrammingError: Incorrect number of bindings。
这不是 bug,是设计限制。别试图绕过,也别去 patch aiosqlite 的 execute 方法。
- ✅ 统一用
?占位,按顺序传参:await db.execute("SELECT * FROM users WHERE status = ? AND age > ?", ("active", 18)) - ✅ 元组或列表都行,但别传字典(除非你自己拆成位置参数)
- ⚠️ 注意:如果参数只有一个,记得加逗号写成
(value,),否则(value)是普通括号,不是元组 → 参数个数对不上
事务控制要显式 commit(),autocommit=False 是默认且不可改
aiosqlite 没有 autocommit=True 模式,所有连接默认都是事务模式。这意味着:哪怕你只执行一条 INSERT,不 commit() 就看不到数据,其他连接也查不到——而且连接关闭时不会自动提交,只会回滚。
这点和 Flask-SQLAlchemy 或 Django ORM 的“隐式提交”习惯完全不同,容易让人误以为写入失败。
- ✅ 写操作后必须显式
await db.commit() - ✅ 如果想批量插入提效,用
executemany()+ 一次commit(),别每条都 commit - ✅ 出错时用
await db.rollback(),但注意:异常发生后连接可能已处于不可用状态,建议在async with块内处理 - ⚠️ 注意:
CREATE TABLE等 DDL 语句也受事务控制,建表后不 commit,别的连接看不到新表
真正麻烦的不是语法,是 SQLite 本身的并发模型和 aiosqlite 对它的裸露程度——它不帮你做连接池、不自动重试、不隔离 WAL 冲突。用之前得先想清楚:你的“轻量级 Web 应用”到底有多少并发写请求,是不是真适合 SQLite。


















