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

一、事务处理核心流程

1. 标准事务生命周期(增、删、改)

复制代码
# 顺序:标记操作 → 执行SQL并提交 → 刷新对象
async with AsyncSessionLocal() as db:
    # ① 标记操作(内存中记录,未发SQL)
    db.add(new_object)                # 新增
    await db.delete(existing_object)  # 删除
    # 或者:stmt = update(...).where(...);await db.execute(stmt)  # 更新
    
    # ② 提交事务(发送SQL到数据库,永久落盘)
    await db.commit()                 
    
    # ③ 刷新对象(可选,从数据库加载最新值,如自增ID)
    await db.refresh(new_object)      

2. 查询流程(只读操作)

复制代码
# 查询通常不需要 commit,只需执行并读取结果
result = await db.execute(select(News).where(...))  # 执行查询,返回 Result 对象
items = result.scalars().all()                       # 提取 Python 对象列表

二、各方法作用详解

方法 调用时机 作用 是否发送SQL
db.add(obj) 新增数据时 将对象标记为"待插入",加入会话的工作队列。 ❌ 否
db.add_all([obj1, obj2]) 批量新增 将多个对象标记为"待插入"。 ❌ 否
await db.delete(obj) 删除数据时 将对象标记为"待删除"。 ❌ 否
await db.execute(stmt) 执行任意SQL(含select/update/delete/insert) 1. 将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. 新增 + 获取自增ID

复制代码
new_news = News(title="标题", content="内容")
db.add(new_news)
await db.commit()           # 此时数据库已插入,ID已生成
await db.refresh(new_news)  # 将生成的ID加载到本地对象
return new_news.id

2. 更新(方式一:对象属性修改)

复制代码
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(views=News.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()
相关推荐
AIgorithmGEEK4 小时前
MySQL 索引全解(下):建、查、删实战与知识速查表
数据库·mysql·b+树·索引
唠点键盘之外的6 小时前
26 向量数据库实战:从 0 搭一条能用的检索链路(pgvector + Spring AI)
数据库·人工智能·spring
云和恩墨7 小时前
数据库监控简史:监控不止于告警——从图表大爆发到健康管理闭环
数据库
ly76897 小时前
MongoDB 事务开销实测:快照隔离下的写冲突、重试与分片事务边界
数据库·mongodb·事务·分片集群·快照隔离·写冲突
豆角焖肉7 小时前
Spring AOP 自定义注解实现系统操作日志
数据库·自定义注解·springaop·操作日志·aop 切面
金伟API10248 小时前
不会写复杂SQL怎么办?
数据库·sql
执笔为剑9 小时前
2.1.2-1、V8R3迁移到V8R6-Oracle兼容特性
数据库
江湖有缘9 小时前
Docker实战 | 使用Docker部署rmoments社交平台
jvm·docker·oracle
geovindu9 小时前
sql:Search-Optimized SQL Queries using mysql 9.0
android·数据库·sql·mysql·数据库开发·数据库架构
for_ever_love__9 小时前
MySQL SELECT 与 WHERE 优化实战:可搜索条件、联合索引与执行计划
数据库·mysql·oracle·select·where·条件优化·查询优化技巧