必须用 yield + try/finally,否则连接不释放导致连接池耗尽;直接 return 会使 session 无法自动关闭,引发 timeouterror。

直接用 Depends(get_db) 就能传数据库连接,但必须配 yield + try/finally,否则连接不释放、池子会爆。
为什么不能直接 return 数据库 session
每次 get_db() 被调用时,SessionLocal() 都会新建一个 session 实例。如果只用 return,FastAPI 拿到 session 后就不管了——连接不会关,事务不会 rollback,连接池里的空闲连接数会持续上涨,直到拒绝新连接。
常见错误现象:sqlalchemy.exc.TimeoutError: QueuePool limit of size 5 overflow 10 reached
正确做法是用 yield 让 FastAPI 在路径函数执行完后自动触发清理逻辑:
-
yield db把 session 注入到路由参数中 -
finally: db.close()确保无论是否出错,session 都被关闭 - 注意:不是
db.rollback()或db.commit()——这些该由业务层显式控制
get_db 函数怎么写才安全
标准写法(同步版):
from sqlalchemy.orm import Session
from myapp.db import SessionLocal
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
异步版(搭配 AsyncSession):
from sqlalchemy.ext.asyncio import AsyncSession
from myapp.db import async_session
async def get_db():
async with async_session() as db:
yield db
关键点:
- 不要在
yield前做db.begin()——事务边界应由路径函数或服务层决定 - 不要在
yield后写业务逻辑 ——那部分代码在响应已发回客户端后才执行 - 若依赖里抛了
HTTPException,finally仍会执行;但若yield后直接raise,客户端可能收不到错误(见下一条)
Depends(get_db) 在路由里怎么用
类型注解必须匹配 yield 的返回值类型,否则 FastAPI 不识别:
@app.get("/users/{user_id}")
def get_user(user_id: int, db: Session = Depends(get_db)):
return db.query(User).filter(User.id == user_id).first()
注意:
-
db: Session中的Session类型要和yield db的实际类型一致(比如别写成AsyncSession却用同步SessionLocal) - 同一个请求内多次
Depends(get_db)(比如嵌套依赖里也用了)只会执行一次get_db,FastAPI 自动缓存结果 - 别把
get_db包进闭包或 lambda ——FastAPI 判定“相同依赖”靠的是 callable 对象身份,不是内容
yield 后抛异常会导致什么
这是最容易被忽略的坑:在 yield 后抛 HTTPException,客户端大概率收到 200 响应 + 正常数据,而不是预期的 400/403。
原因:FastAPI 已经把响应发出去了,yield 后的代码属于“清理阶段”,此时再 raise 异常不会改写 HTTP 状态码。
所以:
- 权限校验、参数预处理等逻辑必须放在
yield前 -
finally只做资源清理,别放业务判断 - 真需要在清理阶段中断流程(比如强制回滚),得用
db.rollback()+ 日志,而不是抛异常
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











