只要应用开始保存数据,数据库和 ORM 就迟早会进入你的视野。SQLAlchemy 是 Python 生态里最重要的数据库工具之一,但很多初学者第一次接触时,往往会被模型、会话、事务这些概念弄得有些割裂。
这一节我们会先不求面面俱到,而是围绕最核心的心智模型展开:模型怎么定义、查询怎么组织、事务如何提交与回滚,以及 ORM 和原生 SQL 之间到底应该怎样分工。
ORM 在项目里扮演什么角色?
ORM 的核心目标,是在“关系型数据库”和“应用里的对象模型”之间建立一层更自然的映射。
它并不是为了让你彻底忘掉 SQL,而是让常见的数据读写、结构组织和关系表达更容易融入应用代码。
所以成熟的使用方式,不是把 ORM 当作“永远不用理解数据库”的遮羞布,而是把它当成提升开发效率和组织能力的一层抽象。
SQLAlchemy 的基本组成
SQLAlchemy 之所以一开始看起来复杂,是因为它并不只是一个“查表工具”,而是覆盖了:
- 模型定义;
- 会话管理;
- 查询表达;
- 事务处理;
- 与数据库方言交互。
所以学习它时,最好不要把 API 一个个孤立记忆,而是先抓住主线:应用如何安全地建立连接、定义模型、执行查询并提交事务。
模型定义与字段映射
模型定义解决的是“数据库表结构如何被应用中的类表达出来”。
字段类型、主键、唯一约束、默认值、索引、关系字段,这些都不只是数据库概念,同时也是业务模型约束的一部分。
所以写模型时要有两个视角:
- 数据库存储视角;
- 业务语义视角。
如果只顾着“能存进去”,却不关心字段命名、约束边界和关系表达,后续模型很容易失去可读性。
一个非常简化的模型示例如下:
from sqlalchemy import String, Text
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = "articles"
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(200), unique=True)
content: Mapped[str] = mapped_column(Text())这个例子看起来只有几个字段,但已经体现了 ORM 模型的几个关键点:
- 类名是应用里的对象语义;
- 表名和列定义对应数据库结构;
- 类型、长度、唯一约束等信息一起进入模型层。
Session、查询与事务处理
新增、修改与删除
SQLAlchemy 里的 Session 可以先理解成“数据库交互上下文”。它不是简单的连接句柄,而是围绕对象状态、查询行为和事务边界组织起来的一层核心机制。
新增、修改、删除表面是不同动作,但它们都依赖同一个关键前提:你需要清楚当前对象状态和事务边界。
提交与回滚
这也是为什么事务意识非常重要。
提交意味着把当前这一批更改真正持久化;回滚则意味着这批更改作废。
如果你没有明确事务边界,代码就很容易出现:
- 某些更新成功了,某些失败了;
- 失败后状态没恢复清楚;
- 同一请求里多个数据库动作互相污染。
所以学习 SQLAlchemy,真正要建立的不是“会增删改查”,而是“会管理一次安全的数据交互流程”。
下面是一段最小交互示例:
from sqlalchemy import create_engine, select
from sqlalchemy.orm import Session
engine = create_engine("sqlite:///blog.db", echo=False)
with Session(engine) as session:
try:
article = Article(title="SQLAlchemy Intro", content="hello")
session.add(article)
session.commit()
stmt = select(Article).where(Article.title == "SQLAlchemy Intro")
saved_article = session.scalar(stmt)
print(saved_article.title)
except Exception:
session.rollback()
raise这段代码最值得记住的不是每个 API 名字,而是这条主线:
- 打开一次明确的 Session;
- 在 Session 内完成一组相关数据库动作;
- 成功就提交;
- 出错就回滚。
ORM 与原生 SQL 的边界
ORM 很方便,但也不是所有场景都必须强行用 ORM 表达。
例如:
- 极其复杂的查询;
- 特定数据库方言能力;
- 对性能有明确要求的统计分析 SQL;
这些场景里,适度使用原生 SQL 往往更直接。
真正成熟的边界是:
- 常规业务读写优先用 ORM 提升结构清晰度;
- 复杂场景保留回到 SQL 的能力;
- 不为了“纯粹 ORM”牺牲可读性和可控性。
总结与预告
这一节我们围绕 SQLAlchemy 建立了 ORM 的基本认知,不再把模型、会话和事务看成零散 API,而是把它们放回“应用如何安全地读写数据”这个核心问题里。
下一节我们会把 FastAPI 和 SQLAlchemy 放到同一个实战场景下,用 Blog API 作为载体,先完成项目开工前的前置准备。