应避免在async def中直接使用sqlite3.connect(),因其阻塞特性会导致“假异步”;推荐开发用aiosqlite、生产用postgresql+asyncpg,并确保sqlalchemy 2.0全程异步配置。

async def里用sqlite3.connect()就卡死
SQLite 是纯文件数据库,sqlite3.connect() 默认是同步阻塞调用,哪怕加了 isolation_level=None 也拦不住磁盘写入锁。一个请求执行 INSERT,其他并发请求全得排队等它释放文件句柄——这不是慢,是“假异步”。
常见错误现象:database is locked 错误频发、压测时吞吐量上不去、uvicorn 日志里请求时间戳明显串行。
- 别在
async def路由里直接调用sqlite3.connect()或cursor.execute() - 开发阶段可用
aiosqlite替代(它封装了线程池 +await接口) - 生产环境建议换 PostgreSQL +
asyncpg,SQLite 本质就不适合高并发
import aiosqlite
<p>@app.get("/users")
async def list_users():
async with aiosqlite.connect("app.db") as db:
async with db.execute("SELECT * FROM users") as cursor:
rows = await cursor.fetchall()
return rows</p>
SQLAlchemy 2.0 AsyncSession 必须配 async_engine
用 SQLAlchemy 2.0 做异步 ORM,光写 async def 不够,底层引擎和会话必须全是异步的。如果 create_async_engine() 没配对,或者 sessionmaker() 用了同步版本,await session.execute(...) 表面能跑,实际还是走线程池模拟,没真正释放事件循环。
容易踩的坑:把 create_engine()(同步)和 AsyncSession 混用,报错不明显,但性能和同步无异。
-
create_async_engine()的 URL 必须带+aiomysql/+asyncpg等异步驱动后缀 -
sessionmaker()必须传class_=AsyncSession,不能漏 - 所有数据库操作必须用
await,包括session.commit()和session.refresh()
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
<p>engine = create_async<em>engine("postgresql+asyncpg://user:pass@localhost/db")
AsyncSessionLocal = sessionmaker(engine, class</em>=AsyncSession)</p><p>@app.get("/items")
async def read_items():
async with AsyncSessionLocal() as session:
result = await session.execute(select(Item))
return result.scalars().all()</p>
别让 N+1 查询拖垮整个事件循环
N+1 查询本身不是异步问题,但它会让单次请求耗时拉长,间接导致协程长时间占用事件循环,其他请求被迫等待——尤其在分页查列表+嵌套关系时,await session.get() 每次都触发一次新查询,叠加起来就是“软阻塞”。
典型场景:返回用户列表,每个用户带订单数;不优化就会查 1 次用户 + N 次 SELECT COUNT(*) FROM orders WHERE user_id = ?。
- 用
selectinload()或joinedload()一次性预加载关联数据 - 避免在循环里写
await session.get(),改用select().where(...).in_([...])批量查 - 聚合统计类需求(如 count、sum),直接用
func.count()在 SQL 层算,别拉到 Python 里 for 循环
依赖注入里别偷偷 new 连接
FastAPI 的 Depends 函数如果每次调用都新建数据库连接(比如在函数体内写 AsyncIOMotorClient() 或 create_async_engine()),不仅内存泄漏,还会快速耗尽连接池,后续请求直接卡在获取连接这一步。
更隐蔽的问题:把 db["collection"] 提前赋值成全局变量,多个请求共用同一个 collection 实例,在多租户或动态 DB 名场景下会串库。
- 数据库客户端/引擎必须是全局单例,启动时创建,关机时
await client.close() -
Depends函数只负责从单例里取 session 或 client,不做初始化 - 用
lifespan管理生命周期,别靠 try/finally 手动关
真正难处理的是混合负载:既要低延迟响应,又要跑报表类重查询。这时候不能只靠“改成 async”,得拆——重任务扔进后台任务队列,接口只返回任务 ID。否则再好的异步库,也扛不住 CPU 密集型操作霸占事件循环。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











