写FastAPI的数据库操作,绕不开一个现实问题:这东西的异步特性太强了,以至于很多从Flask或Django转过来的人,第一反应是“这玩意怎么跟我想的不一样”。你写惯了同步代码,突然让你在async函数里操作数据库,一不小心就踩坑。但反过来,一旦你把FastAPI的异步数据库玩法摸透了,那种丝滑感,确实比传统同步框架高出一个档次。今天咱们不聊虚的,直接进代码,把增删改查和异步实战掰开揉碎了讲。

先说最基础的,你新建一个FastAPI项目,第一件事不是写接口,而是把数据库连接准备好。现在主流选择是SQLAlchemy 2.0加asyncpg驱动。很多人上来就照着老教程配了个同步引擎,然后硬塞进async函数里,结果接口一跑起来就报错“greenlet spawn”之类的问题。其实解法很简单:用替代,再把sessionmaker的class参数改成。就这么两步,你就能在async环境里操作PostgreSQL或MySQL了。我见过太多人卡在这一步,其实就是文档没读仔细。
配置好引擎之后,接下来是定义模型。这里有个细节,SQLAlchemy 2.0的声明式写法变了,直接写在类属性上,类型用和来标注。比如你定义一个用户表,,这种写法一开始可能觉得啰嗦,但习惯之后你会觉得它比旧版本清晰得多。尤其是类型标注明确之后,IDE的补全和类型检查能帮你省不少事。而且,异步模型和同步模型的定义方式完全一样,不需要额外改动,这一点SQLAlchemy做得挺良心。
接下来是增删改查的实战。先说增。在异步session里,你要先,然后,。注意,commit必须await,否则操作不会真正落库。有人会问,能不能用替代?可以,但flush只是把数据发到数据库,事务还没提交,如果你后面还要查询这条数据,flush之后是可以查到的。但如果你只是单纯新增,建议直接commit,省心。还有个小坑:如果你在async函数里用了但忘了await,FastAPI不会报错,但数据就卡在内存里,接口返回了,数据库里啥也没有。这种bug排查起来特别费劲。
删和改的逻辑其实差不多。删的话,先查出来再删,比如,然后,。改的话,直接查出来,修改属性,commit就行。但这里有个性能问题,如果你每次改字段都先查一遍再改,接口响应就会慢。优化思路是直接用语句,比如,然后commit。这种方式省了一次查询,在高并发场景下,差距就出来了。
查询这块,异步和同步最大的区别在于,你不能直接用,得用语句配合。比如查所有用户:,然后。如果你要分页,加和就行。还有一个容易忽略的点,SQLAlchemy 2.0的懒加载在异步里会出问题。比如你定义了一个外键关联,查完用户后想访问他的文章列表,如果没提前用或加载,访问的时候会报“MissingGreenlet”错误。这个坑几乎每个新手都会踩,所以记住一个原则:异步查询里,凡是需要关联的数据,一律用显式加载。
说完基础CRUD,聊聊实战中常见的性能优化。FastAPI的异步优势在于,数据库操作不阻塞事件循环。但如果你写的代码是同步的,比如在async函数里直接调一个同步的ORM操作,那整个事件循环就被卡住了,FastAPI的并发优势瞬间消失。所以,要么全部用异步,要么用把同步操作扔到线程池里。但说实话,既然选了FastAPI,就该把异步贯彻到底。另外,连接池的配置也很关键。里可以设置和,默认值偏保守,如果你的应用并发量高,建议适当调大。还有这个参数,它能确保从池里拿到的连接是活的,避免数据库重启后连接失效报错。
再说一个实际项目里很常见的场景:事务控制。有时候一个接口要同时操作多张表,比如下单要扣库存、加订单记录、更新用户积分,这三步必须在一个事务里完成。异步session的事务控制跟同步差不多,只是要手动管理和。推荐用这种上下文管理器写法,它会自动在代码块结束时commit,如果抛异常就自动rollback。这个写法比手动try-except干净多了。另外,如果你用了多个数据库或分库分表,SQLAlchemy的绑定了单个连接,跨库事务就不好搞了。这时候要么牺牲强一致性,用最终一致性方案,要么引入分布式事务框架,那就是另一个话题了。
测试这块也得提一嘴。FastAPI的异步数据库操作,在单元测试里很容易出幺蛾子。你没法直接用pytest的普通函数去测async接口,得装插件,然后给测试函数加。而且数据库连接在测试里最好用独立的测试库,每个测试用例跑完要清库,不然数据互相污染。有个小技巧是,用配合FastAPI的来模拟请求,这样能在不启动真实服务器的情况下测接口。整个过程其实不复杂,但细节多,稍不留神就会在CI里跑出几个flaky测试。
说实话,FastAPI的数据库操作,门槛不在“会不会写”,而在“能不能写出高效且不出错的异步代码”。很多人觉得同步框架稳,异步花里胡哨,但实际生产环境中,异步带来的吞吐量提升是实打实的。尤其是遇到IO密集型的数据库操作,比如批量查询、慢SQL,异步的等待时间能让出事件循环去处理其他请求。快慢不是玄学,是代码里每一处await的选择。你要做的就是多看官方文档,多写小例子去验证自己的理解,踩坑多了自然就熟了。这篇文章给到的知识点,基本覆盖了日常开发90%的数据库操作场景。剩下的10%,等你在真实项目里遇到了,再回来翻文档,那时候你对“FastAPI数据库操作全攻略”这句话的理解,才算真正到位。


