嘿,老朋友!最近是不是也被FastAPI圈粉了?异步、高性能、自动生成API文档,简直像给Web开发装了涡轮增压。但一说到操作数据库,尤其是和PostgreSQL配对时,是不是立刻血压升高?
我刚开始也这样------照着官方文档敲,结果连数据库都连不上;好不容易连上了,查询又报async/await混用的诡异错误;更别提事务回滚时那种"仿佛身体被掏空"的感觉。😫
别急,今天这篇就是来救火的。 咱们从零开始,把FastAPI+PostgreSQL的完整链路捋一遍,把我踩过的坑、总结的经验全掏给你,保证你看完就能上手,少走三个月弯路。
📌 本文能帮你解决: PostgreSQL安装与环境配置;FastAPI如何优雅地异步操作数据库;常见的连接、驱动、事务问题及解决方案;以及一套可以直接复用的代码模板。
🗺️ 咱们的路线图
🔹 为什么要选PostgreSQL?------ 类比一下,它就像数据库界的瑞士军刀
🔹 安装PostgreSQL(偷懒用Docker,省心)
🔹 FastAPI项目初始化 & 依赖选型(这里有个选择困难症必看的建议)
🔹 实战:写一个用户注册/查询接口(代码可直接复制)
🔹 高频问题大复盘(踩坑记录)
🧐 第一部分:为什么是PostgreSQL?
你可以把PostgreSQL想象成一个**"极度守规矩的档案管理员"**------数据完整性、ACID、复杂查询支持得滴水不漏。
相比MySQL,它对JSON、全文检索、地理空间数据的支持更原生,而且这几年性能优化得特别猛。
最关键的是,它和FastAPI的异步生态配合得非常好,后面你会体会到。
⚙️ 第二部分:安装PostgreSQL(Docker一键搞定)
最怕那种"双击安装包一路下一步"然后环境变量配半小时的教程。咱们用Docker,干净利落。
docker run -d \
--name postgres-demo \
-e POSTGRES_PASSWORD=mysecretpassword \
-e POSTGRES_USER=myuser \
-e POSTGRES_DB=mydb \
-p 5432:5432 \
postgres:15
然后你就可以用任何客户端(比如TablePlus 或DBeaver )连上localhost:5432验证一下。记得密码别写死在代码里,后面咱们用环境变量。
敲黑板: 本地开发千万别用root用户,上面我特意建了普通用户myuser,权限最小化原则。
📦 第三部分:FastAPI项目初始化
创建一个新目录,弄个虚拟环境,然后装依赖。这里我推荐两个库:
✅ asyncpg ------ PostgreSQL的异步驱动,性能爆表。
✅ databases ------ 封装了连接池和查询,让你能用async/await执行SQL,还支持SQLAlchemy Core(可选)。
当初我图省事直接用了同步的psycopg2,结果FastAPI异步线程被阻塞,性能直接打骨折。所以,一定一定要用异步驱动!
安装命令:
pip install fastapi uvicorn databases[asyncpg] python-dotenv
💻 第四部分:写代码,让FastAPI和PG连上线
先建一个.env文件存放敏感信息:
DATABASE_URL=postgresql://myuser:mysecretpassword@localhost/mydb
然后写主程序main.py:
import os
from fastapi import FastAPI
from contextlib import asynccontextmanager
from databases import Database
from dotenv import load_dotenv
load_dotenv()
DATABASE_URL = os.getenv("DATABASE_URL")
database = Database(DATABASE_URL)
@asynccontextmanager
async def lifespan(app: FastAPI):
await database.connect()
# 创建表(实际项目用Alembic,这里演示直接执行SQL)
query = """CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL
);"""
await database.execute(query=query)
print('数据表创建完成!')
yield
await database.disconnect()
app = FastAPI(lifespan=lifespan)
@app.get("/users")
async def get_users():
query = "SELECT id, username, email FROM users"
results = await database.fetch_all(query=query)
return [dict(r) for r in results]
@app.post("/users")
async def create_user(username: str, email: str):
# 简单的插入,实际要加异常处理
query = "INSERT INTO users(username, email) VALUES (:username, :email) RETURNING id"
values = {"username": username, "email": email}
user_id = await database.execute(query=query, values=values)
return {"id": user_id, "username": username, "email": email}
启动服务:uvicorn main:app --reload。打开http://localhost:8000/docs,你就能看到自动生成的API文档,试一下POST和GET,是不是很爽?
⚠️ 第五部分:那些年我踩过的坑(精华)
🚨 坑1:连接被拒绝
现象:ConnectionRefusedError。大概率是Docker容器端口没映射出来,或者PostgreSQL配置只绑定了127.0.0.1。用Docker一定要加-p 5432:5432。另外检查防火墙。
🚨 坑2:asyncpg.exceptions.InvalidPasswordError
密码错误?其实很多时候是因为URL格式不对。注意 :postgresql://user:pass@host/db,特殊字符要URL编码。
🚨 坑3:在异步函数里用了同步的psycopg2连接
这会导致事件循环阻塞,性能急剧下降。解决方案就是全程用asyncpg或databases。
🚨 坑4:事务忘记commit?
用database.transaction()上下文管理器最安全:
async with database.transaction():
await database.execute(query1)
await database.execute(query2) # 如果出错,自动回滚
🚨 坑5:连接池耗尽
默认连接池大小可能不够,高并发时需调整:
database = Database(DATABASE_URL, min_size=5, max_size=20)
🎯 最后啰嗦一句
其实FastAPI+PostgreSQL的组合非常稳健,只要你把异步的思维刻在脑子里,把连接池、事务这些基础概念搞扎实,线上跑起来比同步框架省心得多。后续有机会咱们再聊Alembic迁移、单元测试、性能压测 这些进阶内容,如果你不想再踩坑,记得🌟关注我,别走散咯!
嘿,老朋友,如果你也在折腾FastAPI和数据库,欢迎留言聊聊你遇到的怪问题。觉得有用的话,点个赞、关注一下,让更多小伙伴别掉坑里~