FastAPI 全栈后端(三):数据库与 ORM

创作者: Yardon | GitHub: github.com/YardonYan | 版本: v1.0 |



ORM 是什么,为什么需要它

ORM(Object-Relational Mapping)像是数据库和 Python 对象之间的翻译官:

复制代码
Python:  user.name = "Yardon"
         ↓ (ORM 翻译)
SQL:     UPDATE users SET name = 'Yardon' WHERE id = 1;

不用写裸 SQL,不需要手动拼接查询字符串,不用处理不同数据库的方言差异。同时 ORM 自动帮你防 SQL 注入。


SQLAlchemy 2.0 快速上手

python 复制代码
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

DATABASE_URL = "postgresql+asyncpg://user:pass@localhost/dbname"

engine = create_async_engine(DATABASE_URL, echo=False)

class Base(DeclarativeBase):
    pass

async def get_db():
    async with AsyncSession(engine) as session:
        yield session

在 FastAPI 中注入数据库会话

python 复制代码
from fastapi import Depends

@app.get("/users")
async def list_users(db: AsyncSession = Depends(get_db)):
    result = await db.execute(select(User).limit(10))
    return result.scalars().all()

Depends 是 FastAPI 的依赖注入系统。get_db 被调用后返回一个数据库会话,路由函数参数中声明 db: AsyncSession 就能拿到它。


定义模型与关系

python 复制代码
class User(Base):
    __tablename__ = "users"

    id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
    username: Mapped[str] = mapped_column(String(50), unique=True, index=True)
    email: Mapped[str] = mapped_column(String(120))
    created_at: Mapped[datetime] = mapped_column(server_default=func.now())

    # 一对多:一个用户有多篇文章
    posts: Mapped[list["Post"]] = relationship(back_populates="author")

class Post(Base):
    __tablename__ = "posts"

    id: Mapped[int] = mapped_column(primary_key=True)
    title: Mapped[str] = mapped_column(String(200))
    content: Mapped[str] = mapped_column(Text)
    user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))

    # 反向关系
    author: Mapped["User"] = relationship(back_populates="posts")

异步数据库操作

python 复制代码
# 创建
new_user = User(username="Yardon", email="y@example.com")
db.add(new_user)
await db.commit()

# 查询
result = await db.execute(select(User).where(User.id == 1))
user = result.scalar_one_or_none()

# 分页
result = await db.execute(
    select(User).offset(skip).limit(limit).order_by(User.created_at.desc())
)

# 更新
user.email = "new@example.com"
await db.commit()

# 删除
await db.delete(user)
await db.commit()

数据库迁移:Alembic

数据库表结构会随着项目演进不断变化------加字段、改类型、建新表。Alembic 帮你管理这些变更。

bash 复制代码
pip install alembic
alembic init alembic
bash 复制代码
# 修改模型后:
alembic revision --autogenerate -m "add users table"
alembic upgrade head    # 应用迁移
alembic downgrade -1    # 回滚一步(出问题时救命)

查询优化:N+1 问题

python 复制代码
# ❌ N+1 问题
users = await db.execute(select(User))
for user in users.scalars():
    posts = await db.execute(
        select(Post).where(Post.user_id == user.id)  # 每个用户1次查询!
    )

# ✅ 预加载关系
users = await db.execute(
    select(User).options(selectinload(User.posts))
)
for user in users.scalars():
    print(user.posts)  # 已经在第一步查好了

N+1 问题就像去图书馆借 10 本书,你不是一次拿 10 本,而是拿一本回家、再来拿第二本、再来拿第三本------效率极低。selectinload 就是一次把关联数据全查出来。


连接池与事务管理

python 复制代码
engine = create_async_engine(
    DATABASE_URL,
    pool_size=10,       # 常驻连接数
    max_overflow=20,    # 突发额外连接数
    pool_recycle=3600,  # 连接回收时间(秒)
)

事务管理:

python 复制代码
async def transfer(sender_id, receiver_id, amount, db):
    async with db.begin():  # 自动 commit/rollback
        sender = await db.get(User, sender_id)
        receiver = await db.get(User, receiver_id)
        sender.balance -= amount
        receiver.balance += amount
        # 如果中间出错,两边都不会被修改

本章小结

SQLAlchemy 2.0 + asyncpg 是 FastAPI 的最佳数据库搭档。记住三条:用 selectinload 避免 N+1、用 Alembic 管理迁移、用 async with db.begin() 保证事务一致性。


📌 创作者: Yardon | 🏠 个人网站: GlimmerAI.top

📖 本章是「FastAPI 全栈后端」系列的第 3 章。

🌟 欢迎大家来观看!

相关推荐
动恰客流统计4 分钟前
客流统计如何结合AI分析?从传统计数到智能决策的技术升级路径
数据库·人工智能·边缘计算
kyriewen15 分钟前
我筛了 1400 个 Claude Code Skills,留下 5 个天天在用的
前端·ai编程·claude
JNX_SEMI30 分钟前
AT2401C 2.4GHz 全集成射频前端单芯片技术解析
前端·单片机·嵌入式硬件·物联网·硬件工程
宠友信息44 分钟前
多端数据互通场景下Spring Boot仿小红书源码结构设计
数据库·spring boot·redis·缓存·架构
风曦Kisaki1 小时前
#Linux数据库管理Day06:主从同步与MaxScale读写分离
linux·运维·数据库
anOnion1 小时前
Agentic 前端开发之 实时显示 AI Agent 终端输出
前端·javascript·人工智能
随风一样自由1 小时前
【前端领域】2026最新前端领域全梳理(框架/工具/AI/跨端/底层标准/就业趋势)
前端·人工智能·前端框架
这是个栗子1 小时前
【前端性能优化】优化数据加载:用 Promise.all 从串行到并行
前端·javascript·性能优化·异步编程·前端优化·promise.all
影寂ldy1 小时前
C# try-catch 异常处理全套笔记
服务器·数据库·c#
长不胖的路人甲1 小时前
Redis 缓存的数据持久化方案讲解
数据库·redis·缓存