FastAPI、SQLAlchemy 、Session 速成笔记
Session常用方法有哪些- 每个方法什么时候用
- 在 FastAPI 里怎么组织代码
- 如何避免新手常见坑
- 如何写得像一个“已经上线过项目的人”
一、先记住一句话:Session 是什么
Session 不是简单的“数据库连接”。
你可以把它理解成:
一次业务操作的工作区 + 事务管理器 + ORM 对象状态跟踪器
它负责:
- 管理 ORM 对象
- 管理事务
- 需要时借用数据库连接
- 在
commit()时提交 - 在
rollback()时回滚 - 在
close()时释放资源
在 FastAPI 里通常遵循:
一个请求,一个 Session
二、FastAPI 场景下你真正要会的 Session 方法
先给你一个最实用的结论:
如果是日常 CRUD,最常用的就是这几个:
add()add_all()get()execute()scalars()scalar()commit()rollback()refresh()flush()delete()close()
如果你把这 12 个吃透,已经能完成大多数业务开发。
三、Session 常用方法总表
1. add(obj)
把一个 ORM 对象加入当前 Session 管理。
session.add(user)
用途
- 新增一条记录
- 让某个新对象进入待插入状态
示例
user = User(username="alice", email="alice@example.com")
session.add(user)
session.commit()
注意
add()之后还没真正写入数据库- 真正发
INSERT一般在:flush()commit()- 某些查询触发自动 flush 时
2. add_all(iterable)
批量把多个对象加入 Session。
session.add_all([user1, user2, user3])
示例
users = [
User(username="a"),
User(username="b"),
User(username="c"),
]
session.add_all(users)
session.commit()
老鸟建议
- 少量对象新增可以用
- 超大量批量导入不推荐 ORM
add_all(),更推荐 Core 的insert()
3. get(Model, pk)
按主键获取对象。
user = session.get(User, 1)
特点
- 按主键查最方便
- 优先从 Session 的 identity map 中取
- 找不到返回
None
示例
user = session.get(User, user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
老鸟建议
- 主键查询优先用
get() - 比
select(User).where(User.id == xxx)更直观
4. execute(statement, params=None)
执行 SQLAlchemy 语句或原生 SQL。
result = session.execute(select(User))
或者:
result = session.execute(
text("SELECT * FROM users WHERE id=:id"),
{"id": 1}
)
用途
- 执行 ORM 查询
- 执行 Core 查询
- 执行原生 SQL
- 执行
update()/delete()/insert()
示例
stmt = select(User).where(User.username == "alice")
result = session.execute(stmt)
user = result.scalar_one_or_none()
老鸟建议
- SQLAlchemy 2 风格中,
execute()非常核心 - ORM 查询几乎都围绕它展开
5. commit()
提交当前事务。
session.commit()
发生了什么
通常会先:
flush()把改动发到数据库- 然后提交事务
示例
user = User(username="alice")
session.add(user)
session.commit()
老鸟建议
- 不要到处
commit() - 通常在 service 层 / 请求结束处统一提交
- 一段完整业务逻辑最好只有一个明确提交点
6. rollback()
回滚当前事务。
session.rollback()
用途
- 发生异常时回滚
- 清空当前事务中的未提交修改
示例
try:
session.add(user)
session.commit()
except Exception:
session.rollback()
raise
老鸟建议
- 只要
commit()失败,通常要先rollback() - 否则 Session 可能处于错误状态,后续不能继续正常用
7. refresh(obj)
从数据库重新加载对象最新状态。
session.refresh(user)
用途
- 刚插入后重新加载数据库生成字段
- 确保对象状态和数据库一致
示例
user = User(username="alice")
session.add(user)
session.commit()
session.refresh(user)
print(user.id)
什么时候很有用
- 你要拿数据库生成的:
- 自增主键
- 默认值
- 触发器生成值
- 更新时间字段
老鸟建议
- 在 FastAPI 创建资源时非常常见:
add()commit()refresh()- 返回对象
8. flush()
把当前改动同步到数据库,但不提交事务。
session.flush()
重要理解
flush != commitflush后 SQL 已经发出去了- 但仍然在事务里,之后还能
rollback()
典型场景
场景 1:你要提前拿到自增主键
order = Order(user_id=1)
session.add(order)
session.flush()
print(order.id) # 此时通常已经有 id 了
然后你继续插入订单项:
item = OrderItem(order_id=order.id, product_id=2, qty=3)
session.add(item)
老鸟建议
- 需要“先插父表,再用父表 id 插子表”时,
flush()非常好用 - 不要把
flush()理解成“保存成功” - 真正事务完成还是靠
commit()
9. delete(obj)
删除一个 ORM 对象。
session.delete(user)
示例
user = session.get(User, 1)
if user:
session.delete(user)
session.commit()
注意
- 删除的前提通常是对象先被加载进 Session
- 删除真正生效还是在 flush/commit 时
10. close()
关闭 Session,释放资源。
session.close()
用途
- 请求结束时关闭
- 让连接归还连接池
- 清理 Session 状态
老鸟建议
- FastAPI 里一般用依赖注入自动处理,不手搓
close() - 但你必须知道底层就是要关闭
四、返回结果相关:你会经常一起用到的 Result 方法
虽然它们不是 Session 的方法,但和 session.execute() 总是一起出现,必须掌握。
1. scalar_one()
要求结果恰好一条,否则报错。
user = session.execute(
select(User).where(User.id == 1)
).scalar_one()