必须用create_async_engine创建引擎并传给sessionmaker且显式指定class_=AsyncSession,否则得到同步Session导致运行时错误;URL需带async驱动前缀;expire_on_commit=False关键;AsyncSession需在async函数中对每个操作显式await;FastAPI依赖注入中必须显式close。

必须用 create_async_engine 创建引擎,再传给 sessionmaker 并显式指定 class_=AsyncSession,否则得到的是同步 Session,运行时直接报错。
create_async_engine 是唯一入口,不能复用同步引擎
SQLAlchemy 2.0 的异步支持不是“开关式”的——你不能把 create_engine 返回的 Engine 塞进 sessionmaker 然后指望它变异步。那样会触发 AttributeError: 'Engine' object has no attribute 'connect' 或更隐蔽的 RuntimeError: This engine is not configured for async usage。
-
create_async_engine返回的是AsyncEngine,它内部封装了协程调度逻辑,和asyncpg或aiosqlite驱动深度绑定 - URL 必须带 async 驱动前缀:
postgresql+asyncpg://、sqlite+aiosqlite:///,写成postgresql://会导致静默降级或连接失败 - 同步驱动(如
psycopg2、pysqlite)完全不兼容,装错包就起不来
sessionmaker 必须显式指定 class_=AsyncSession
这是最容易漏掉的关键参数。只写 sessionmaker(bind=engine) 会默认返回同步 Session 类型,哪怕 engine 是 AsyncEngine 也没用。
- 正确写法:
AsyncSessionLocal = sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False) -
expire_on_commit=False很关键:commit 后若仍需访问对象属性(比如返回 JSON),不设这个会触发额外await,导致DetachedInstanceError或阻塞 - 每次请求都应调用
AsyncSessionLocal()获取新实例,不能全局缓存或复用,否则事务隔离失效
AsyncSession 不是“拿来就能 await”的对象
AsyncSession 本身是协程上下文管理器,不是协程。你不能 await session.execute(...) 之前先 await session——那会报 TypeError: object AsyncSession can't be used in 'await' expression。
立即学习“Python免费学习笔记(深入)”;
- 所有数据库操作必须在
async def函数内,且对每个方法显式await:await session.execute()、await session.commit()、await session.refresh(obj) - 查询结果要分两步取:
result = await session.execute(select(User))→users = (await result.scalars()).all();写成result.scalars().all()会返回AsyncIterator,不 await 就拿不到数据 - 禁止混用同步写法:
session.add()后不await session.commit(),或在 async 函数里调session.commit()(没 await)——都会卡住或抛RuntimeWarning
FastAPI 依赖注入中容易漏掉 close
在 FastAPI 里用 Depends 提供 AsyncSession 时,很多人只写 yield session,忘了 await session.close()。
- 后果严重:连接不会归还池中,持续累积直至达到数据库最大连接数,整个服务变慢甚至拒绝响应
- 安全写法是
async with AsyncSessionLocal() as session: yield session,或者手动try/finally+await session.close() - 别依赖 GC 自动回收——异步对象的生命周期必须由开发者显式控制
最常被忽略的一点:异步 Session 的事务边界和连接生命周期是强绑定的,async with 不仅是语法糖,它背后控制着连接获取、事务开启、异常回滚、连接释放四个不可拆分的动作。跳过它,等于把数据库连接池当一次性筷子用。


















