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

🧐 第一部分:为什么是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)
相关推荐
z1234567898612 小时前
2026最新两款AI编程工具深度对比实测
java·数据库·ai编程
程序猿DD12 小时前
一个 API Key,统一调用大模型、生图和联网搜索
数据库·网关
TlSfoward13 小时前
抓包代理链路下的 TLS 指纹变化分析 TLSFOWARD抓包工具
数据库·爬虫·网络协议·搜索引擎·php
数智化管理手记13 小时前
账龄分析手工统计易遗漏?自动账龄分析工具怎么搭建
大数据·网络·数据库·人工智能·数据挖掘
LabVIEW开发14 小时前
NI Package Manager安装LabVIEW时InternalServerError错误
网络·数据库·labview·labview知识·labview功能·labview程序
SelectDB14 小时前
PostgreSQL 实时同步到 Apache Doris:一站式 CDC 解决方案
数据库
Database_Cool_14 小时前
AI Agent 长期记忆怎么存?阿里云 PolarDB-X 对接 Mem0 记忆框架实践
数据库·阿里云
会编程的土豆15 小时前
数据库范式
数据库·oracle
L16247615 小时前
MySQL 全环境生产快速安装 + 完整配置手册(整合国产银河麒麟适配 + 主从补充版)
数据库·mysql
yio_yin15 小时前
Spring事务管理(数据一致性)
数据库·sql·spring