sqlalchemy 2.0异步必须用create_async_engine而非create_engine,url需带async驱动(如postgresql+asyncpg://),session须用async_sessionmaker并配合await操作,事务需显式await session.begin()或用async with session.begin()自动管理。

异步引擎必须用 create_async_engine,不能复用同步引擎
SQLAlchemy 2.0 的异步支持不是给现有 create_engine 加个参数就能开的。你得从头用 create_async_engine 构建引擎,否则会报 AsyncEngine is not a sync engine 这类错误。
常见错误是把同步 URL 直接喂给异步函数,或者试图在 sessionmaker 里传入同步引擎——这会导致运行时直接抛出 AttributeError: 'Engine' object has no attribute 'connect'。
-
create_async_engine返回的是AsyncEngine,它不兼容任何同步调用路径 - URL 必须带 async driver,比如
postgresql+asyncpg://...或sqlite+aiosqlite://...(注意不是sqlite:///) - 同步驱动如
psycopg2、pysqlite无法用于异步引擎,必须换asyncpg或aiosqlite
Session 要用 async_sessionmaker,且必须配合 await 使用
异步 Session 不是线程安全的“即取即用”对象,它本身是协程上下文管理器,所有数据库操作都得显式 await,否则会卡住或报 RuntimeWarning: coroutine 'AsyncSession.execute' was never awaited。
别用 session.query(...) —— 这是 1.x 风格,2.0+ 已移除;也别直接调 session.add() 后就 commit,那只是把对象放进 session 缓存,没真正写库。
- 创建方式:用
async_sessionmaker(bind=engine, expire_on_commit=False),expire_on_commit=False很关键,否则 commit 后再访问对象属性会触发额外 await - 增删改查都要
await:比如await session.execute(...)、await session.commit()、await session.refresh(obj) - 查询结果要手动
scalars()或scalars().all()才能拿到 Python 对象,execute().scalars().first()是常用组合
ORM 查询必须走 select(),不能用字符串 SQL(除非显式声明为 text)
SQLAlchemy 2.0 强推表达式式查询,session.execute("SELECT ...") 这种字符串写法默认被当作文本 SQL 处理,不会做参数绑定或类型校验,容易 SQL 注入,而且返回的是原始 Row,不是 ORM 实例。
如果你要查 ORM 模型实例,必须用 select(MyModel) + session.execute() + scalars() 链式调用,否则拿不到模型对象,只能拿到字段元组。
-
select(User).where(User.id == 1)是标准写法,await session.execute(...)后接.scalars().first() - 想执行原生 SQL?得包装成
text("SELECT ..."),并手动指定参数绑定:await session.execute(text("SELECT * FROM users WHERE id = :id"), {"id": 1}) - 关联查询(joinedload)在异步下仍可用,但必须用
options(joinedload(...)),不能用join()写法,后者只适用于底层语句构造
事务嵌套和异常处理容易漏掉 rollback()
异步 Session 的事务不是自动回滚的。如果 await session.commit() 失败(比如唯一约束冲突),session 会处于不可用状态,后续任何操作都会报 InvalidRequestError: This Session's transaction is closed due to previous exception,但程序不会自动 rollback。
很多人写 try/except 只捕获异常,却忘了在 except 块里加 await session.rollback(),导致 session 卡死、连接泄漏,甚至影响后续请求。
- 务必在
except中调用await session.rollback(),否则该 session 实例基本废了 - 推荐用
async with session.begin():替代手动begin/commit/rollback,它会在异常时自动 rollback,在成功时自动 commit - 注意
session.begin()是协程,必须await;async with语法糖内部已处理,但你要确保外层函数是async def
实际跑起来最常卡在驱动没装对、URL 写错、忘记 await、或者事务没 rollback。尤其本地开发时用 sqlite,很容易忽略 aiosqlite 和 sqlite+aiosqlite:// 这两个硬性要求。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











