ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

FastAPI + SQLAlchemy 异步会话(AsyncSession)核心方法

FastAPI + SQLAlchemy 异步会话(AsyncSession)核心方法 一、事务处理核心流程1. 标准事务生命周期增、删、改# 顺序标记操作 → 执行SQL并提交 → 刷新对象 async with AsyncSessionLocal() as db: # ① 纯内存标记操作不发送SQL不需要 await db.add(new_object) # 新增纯内存 db.add_all([obj1, obj2]) # 批量新增纯内存 # ② 标记删除 自动刷新检查可能发送 SQL需要 await await db.delete(existing_object) # 逻辑标记触发autoflush检查 # 注意delete 虽然逻辑是标记但因为内部可能触发flush所以必须 await # 或者执行更新语句发送SQL需要 await stmt update(...).where(...).values(...) await db.execute(stmt) # 立即发送SQL需要 await # ③ 提交事务发送SQL到数据库永久落盘需要 await await db.commit() # ④ 刷新对象从数据库查回来需要 await await db.refresh(new_object)2. 查询流程只读操作# 查询通常不需要 commit只需执行并读取结果 result await db.execute(select(News).where(...)) # 执行查询返回 Result 对象 items result.scalars().all() # 提取 Python 对象列表二、各方法作用详解方法调用时机作用是否发送SQLdb.add(obj)新增数据时将对象标记为“待插入”加入会话的工作队列。❌ 否db.add_all([obj1, obj2])批量新增将多个对象标记为“待插入”。❌ 否await db.delete(obj)删除数据时将对象标记为“待删除”。❌ 否await db.execute(stmt)执行任意SQL含select/update/delete/insert1. 将SQL语句发送给数据库服务器执行。2. 返回Result对象包含影响行数、游标等。3. 对于update/delete数据在数据库内存Buffer Pool中已变更但事务未提交其他连接不可见。✅ 是await db.commit()必须在所有增、删、改操作之后调用1. 将当前事务中的所有变更add/delete/execute永久写入磁盘。2. 释放数据行上的锁。3. 使变更对其他数据库连接可见。4. 若在此前代码抛异常且未捕获事务会自动回滚所有变更撤销。✅ 是提交指令await db.refresh(obj)调用commit()之后通常是新增/更新后从数据库重新查询该对象的最新状态刷新本地内存属性如获取自增id、数据库默认值、计算列等。✅ 是查询await db.rollback()发生异常需要撤销变更时撤销当前事务中所有未提交的变更利用 Undo Log 回滚数据。✅ 是回滚指令await db.flush()在commit前需要提前获取数据库生成的ID时极少手动调用提前将 SQL 发送到数据库执行写入内存但不提交事务。数据仍处于当前事务中其他连接不可见可通过rollback撤销。✅ 是三、事务自动管理上下文管理器使用async with AsyncSessionLocal() as db:时会自动在代码块结束时执行close()归还连接到池。但它不会自动commit仍需显式调用。若代码块内抛异常且未显式调用commit会话会在关闭时自动执行rollback。四、result.rowcount和commit的关系result.rowcount由execute执行后立即从数据库返回表示本次 SQL 语句影响了数据库内存中的多少行。此值不依赖commit即使未提交值也已获取。commit将内存变更持久化到磁盘并释放锁。若省略commit内存变更会在会话关闭时被rollback撤销。五、典型代码范例增、改、删1. 新增 获取自增IDnew_news News(title标题, content内容) db.add(new_news) await db.commit() # 此时数据库已插入ID已生成 await db.refresh(new_news) # 将生成的ID加载到本地对象 return new_news.id2. 更新方式一对象属性修改result await db.execute(select(News).where(News.id id)) news result.scalar_one() news.title 新标题 await db.commit() # 自动检测到对象变更生成UPDATE发送3. 更新方式二批量更新不查询stmt update(News).where(News.category_id 1).values(viewsNews.views 1) result await db.execute(stmt) await db.commit() return result.rowcount # 返回受影响行数4. 删除news await db.get(News, id) if news: await db.delete(news) await db.commit()
返回列表