databases 卡住常因连接池泄漏,需在应用关闭时调用 await database.disconnect();fetch_all() 返回 list[record],非流式迭代器,大数据量易内存溢出。

asyncpg 和 databases 都用 async,为什么 databases 有时卡住不返回?
因为 databases 默认用的是连接池(Database 实例内部维护),但它的 connect() / disconnect() 不是每次查询都新建连接——它复用池里已建立的连接。如果没显式调用 database.disconnect(),或协程异常退出没触发清理,连接可能滞留、超时、甚至被数据库端断开后 databases 还在等响应。
- 务必在应用生命周期结束时调用
await database.disconnect(),比如 FastAPI 的shutdown事件里 - 单次查询别手动
connect()/disconnect(),那是反模式;直接用database.fetch_one()等方法,它们自动借还连接 - 如果看到
asyncpg.exceptions.TooManyConnectionsError或日志里反复出现connection was closed,八成是连接池泄漏,不是并发太高
用 databases 写 raw SQL,fetch_all() 返回的是 list 还是 AsyncIterator?
是 list,不是流式迭代器。它会把整个结果集一次性加载进内存,然后才返回。这对小表没问题,但查百万行时容易 OOM,且无法 early-exit。
-
fetch_all()→list[Record],适合结果确定、体积可控( - 真要流式处理,得绕过
databases,直接用底层驱动:比如asyncpg.Connection.cursor()或aiosqlite.Cursor的异步迭代支持 -
fetch_val()和fetch_one()同样是一次性取,只是只取一个值或一行,别误以为它们“更轻量”
databases 的 transaction() 块里能嵌套另一个 transaction() 吗?
不能。它不支持真正的嵌套事务(savepoint 是另一回事)。如果你在已开启的事务中再调用 async with database.transaction():,第二个块不会新建事务,而是复用外层上下文——但一旦外层回滚,内层所有操作全丢,且不会报错,容易误判成功。
原本这个程序只是本人两年前初学时练手的,最近拿出来进行了修改,所以叫XmxCms 企业网站管理系统2.0 开发环境:WinXP + VS2008 + SQLServer 2008 + Access开发语言:C#本程序采用 三层架构 + 抽象工厂设计模式 + Linq 实现,目前只做了Access 和 SQL Server ,默认数据库为Access,要更换数据库只需修改web.config 即可
- 需要局部回滚?用
savepoint:比如async with transaction._connection.transaction():(私有 API,不推荐)或干脆换用asyncpg的connection.transaction()+declare_savepoint() -
databases的事务只保证原子性,不提供隔离级别控制,想设REPEATABLE READ?得直接连asyncpg并传参 - 事务块里别混用同步代码(如
time.sleep()),会阻塞整个 event loop,看起来像“卡在事务里”
SQLite 走 databases 的 async 接口,真的异步吗?
不真的异步。SQLite 的磁盘 I/O 本质是同步阻塞的。databases 对 SQLite 的 “async” 实现,是把操作扔进线程池(concurrent.futures.ThreadPoolExecutor)里跑,再用 await 等结果——它只是“假装异步”,不是零拷贝、无调度延迟的真异步。
立即学习“Python免费学习笔记(深入)”;
- 高并发写 SQLite 时,线程池可能成为瓶颈,
asyncpg那种纯异步协议的优势完全体现不出来 - 如果只是本地开发或低流量原型,够用;但上生产、尤其有写压力,别指望
databases+sqlite能扛住,换asyncpg或至少用aiosqlite自己控线程数 -
database.url写成sqlite+aiosqlite:///db.sqlite才启用 aiosqlite 后端;写成sqlite:///db.sqlite用的是默认的同步适配器(会报错)









