11-SQLAlchemy 2.0异步ORM实战指南

SQLAlchemy 2.0异步ORM实战指南

前言

SQLAlchemy 2.0引入了原生异步支持,为高性能数据库操作提供了强大工具。本文将详细介绍如何使用SQLAlchemy 2.0构建异步数据访问层。

适合读者: 后端开发者、数据库工程师


一、模型定义

python 复制代码
# models/user.py
from sqlalchemy import String, Integer, DateTime, Boolean
from sqlalchemy.orm import Mapped, mapped_column
from datetime import datetime
from database import Base

class User(Base):
    __tablename__ = "users"
    
    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    username: Mapped[str] = mapped_column(String(50), unique=True, index=True)
    email: Mapped[str] = mapped_column(String(100), unique=True, index=True)
    password_hash: Mapped[str] = mapped_column(String(255))
    full_name: Mapped[str | None] = mapped_column(String(100))
    is_active: Mapped[bool] = mapped_column(Boolean, default=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
    updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

class Conversation(Base):
    __tablename__ = "conversations"
    
    id: Mapped[str] = mapped_column(String(36), primary_key=True)
    user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"))
    title: Mapped[str] = mapped_column(String(200))
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
    updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

二、CRUD操作

python 复制代码
# crud/user.py
from sqlalchemy import select, update, delete
from sqlalchemy.ext.asyncio import AsyncSession

async def create_user(db: AsyncSession, username: str, email: str, password_hash: str):
    user = User(username=username, email=email, password_hash=password_hash)
    db.add(user)
    await db.flush()
    await db.refresh(user)
    return user

async def get_user_by_id(db: AsyncSession, user_id: int):
    result = await db.execute(select(User).where(User.id == user_id))
    return result.scalar_one_or_none()

async def get_users(db: AsyncSession, skip: int = 0, limit: int = 100):
    result = await db.execute(select(User).offset(skip).limit(limit))
    return result.scalars().all()

async def update_user(db: AsyncSession, user_id: int, **kwargs):
    await db.execute(
        update(User).where(User.id == user_id).values(**kwargs)
    )
    return await get_user_by_id(db, user_id)

async def delete_user(db: AsyncSession, user_id: int):
    await db.execute(delete(User).where(User.id == user_id))

三、关系查询

python 复制代码
# 一对多关系
from sqlalchemy.orm import relationship

class User(Base):
    __tablename__ = "users"
    id: Mapped[int] = mapped_column(primary_key=True)
    conversations: Mapped[list["Conversation"]] = relationship(back_populates="user")

class Conversation(Base):
    __tablename__ = "conversations"
    id: Mapped[str] = mapped_column(primary_key=True)
    user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
    user: Mapped["User"] = relationship(back_populates="conversations")

# 查询用户及其对话
async def get_user_with_conversations(db: AsyncSession, user_id: int):
    result = await db.execute(
        select(User)
        .options(selectinload(User.conversations))
        .where(User.id == user_id)
    )
    return result.scalar_one_or_none()

四、事务管理

python 复制代码
async def transfer_conversation(
    db: AsyncSession,
    conversation_id: str,
    from_user_id: int,
    to_user_id: int
):
    async with db.begin():
        # 检查对话是否存在
        conv = await get_conversation(db, conversation_id)
        if not conv or conv.user_id != from_user_id:
            raise ValueError("对话不存在或无权限")
        
        # 更新对话所有者
        conv.user_id = to_user_id
        await db.flush()

五、性能优化

python 复制代码
# 批量插入
async def batch_create_messages(db: AsyncSession, messages: list[dict]):
    db.add_all([Message(**msg) for msg in messages])
    await db.flush()

# 预加载关系
from sqlalchemy.orm import selectinload, joinedload

async def get_conversations_with_messages(db: AsyncSession, user_id: int):
    result = await db.execute(
        select(Conversation)
        .options(selectinload(Conversation.messages))
        .where(Conversation.user_id == user_id)
    )
    return result.scalars().all()

下一篇预告: 《Redis缓存策略:提升API响应速度10倍》

相关推荐
三声三视6 小时前
我弃了“全自主 Agent“:一次误退款,让我给所有危险工具加了道人工闸
人工智能·ai·aigc
Python私教6 小时前
前端转 AI 全栈:别只做聊天框,SSE 与审批流才是分水岭
前端·人工智能
机器人落地派6 小时前
机器人项目变更闭环检查表:别只写“已经改了”
人工智能·机器人·人形机器人·机器人落地·评审
小园子的小菜6 小时前
从Prompt到Loop:AI工程化四层范式完全指南(Prompt/Context/Harness/Loop)
人工智能·prompt
canonical-entropy6 小时前
Mission Driver:Loop Engineering 的一种通用参考实现
大数据·人工智能·ai-agent·可逆计算·nop平台·harness
cn分享汇6 小时前
启锐H20照片打印机,随时实地轻松打印
人工智能
Python私教6 小时前
AI Agent 为什么总在最后一步失败?从启动异常到可恢复工作流
人工智能
武子康6 小时前
生产环境的模型路由不是一次难度分类:从硬约束可行域到状态检查点升级
人工智能·llm·agent
m沐沐6 小时前
【计算机视觉】OpenCV 物体跟踪——原理、算法与CSRT跟踪器实战
人工智能·python·深度学习·opencv·算法·计算机视觉·人脸识别
rain_sxr6 小时前
一个模型打天下:多模型路由前端的策略层与降级兜底
人工智能