FastAPI + PostgreSQL 实战:从入门到不踩坑,一次讲透

嘿,老朋友!最近是不是也被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

然后你就可以用任何客户端(比如TablePlusDBeaver )连上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连接

这会导致事件循环阻塞,性能急剧下降。解决方案就是全程用asyncpgdatabases

🚨 坑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和数据库,欢迎留言聊聊你遇到的怪问题。觉得有用的话,点个赞、关注一下,让更多小伙伴别掉坑里~

相关推荐
用户8356290780516 小时前
使用 C# 在 Excel 中创建数据透视表
后端·python
IvorySQL7 小时前
PostgreSQL 技术日报 (3月10日)|IIoT 性能瓶颈与内核优化新讨论
数据库·postgresql·开源
码路飞9 小时前
FastMCP 实战:一个 .py 文件,给 Claude Code 装上 3 个超实用工具
python·ai编程·mcp
dev派11 小时前
AI Agent 系统中的常用 Workflow 模式(2) Evaluator-Optimizer模式
python·langchain
前端付豪13 小时前
AI 数学辅导老师项目构想和初始化
前端·后端·python
用户03321266636713 小时前
将 PDF 文档转换为图片【Python 教程】
python
悟空爬虫14 小时前
UV实战教程,我啥要从Anaconda切换到uv来管理包?
python
dev派15 小时前
AI Agent 系统中的常用 Workflow 模式(1)
python·langchain
小瓦码J码15 小时前
PostgreSQL表名超长踩坑记
数据库·postgresql