数据库 / 闯关模式
关系型数据库和 SQL 够用基础
先补表、行、列、主键、外键、SQL、索引、事务和 ORM 对应关系。
一句话:关系型数据库像一组有规则的表格,SQL 是你向这些表格查询、写入、修改和删除数据时使用的标准语言。
本篇学完你会什么:能看懂表、行、列、主键、外键、索引、事务这些词,知道 SQLAlchemy 背后其实是在帮你生成和执行 SQL。
1. 为什么学 ORM 前要先懂一点 SQL
FastAPI 项目里常用 SQLAlchemy 操作数据库。它很好用,但它不是“魔法数据库”,它只是帮你用 Python 写出数据库能听懂的 SQL。
如果完全不懂 SQL,看到这些代码会很晕:
stmt = select(User).where(User.username == "tom")
result = await db.execute(stmt)其实它大概对应:
SELECT * FROM users WHERE username = 'tom';所以这篇不追求把 SQL 学深,而是先补够后端开发最常用的那一层。
2. 表、行、列是什么
关系型数据库最基本的单位是表。
比如用户表 users:
| id | username | is_active | |
|---|---|---|---|
| 1 | tom | tom@example.com | true |
| 2 | lucy | lucy@example.com | true |
大白话:
| 名词 | 像什么 | 例子 |
|---|---|---|
| 表 table | Excel 的一个工作表 | users |
| 行 row | 一条数据 | id 为 1 的用户 |
| 列 column | 一个字段 | username |
| 字段类型 | 这一列能放什么 | int、varchar、bool |
后端接口里返回的 JSON,很多时候就是从数据库的一行或多行整理出来的。
3. 主键和唯一约束
主键是每一行数据的身份证。
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(32) NOT NULL
);id 是主键,意思是:
- 每个用户都有自己的
id id不能重复- 查询、修改、删除时经常靠它定位数据
唯一约束是“这个字段也不能重复”。
CREATE UNIQUE INDEX ix_users_username ON users(username);比如用户名不能重复、邮箱不能重复,就会用唯一约束。
4. 外键和表关系
真实业务通常不止一张表。
比如文章表 articles:
| id | title | author_id |
|---|---|---|
| 10 | FastAPI 入门 | 1 |
这里的 author_id = 1 指向 users.id = 1。
大白话:文章表不需要把作者所有信息复制一遍,只要记住“作者是谁的 id”。
常见关系:
| 关系 | 大白话 | 例子 |
|---|---|---|
| 一对多 | 一个用户有多篇文章 | users -> articles |
| 多对一 | 多篇文章属于一个用户 | articles -> users |
| 多对多 | 用户和角色互相关联 | users <-> roles |
初学阶段先吃透一对多就够了。
5. 最常用的 SQL
查询
SELECT id, username FROM users WHERE id = 1;意思:从 users 表里查 id 为 1 的用户,只拿 id 和 username。
新增
INSERT INTO users (username, email)
VALUES ('tom', 'tom@example.com');意思:新增一行用户数据。
修改
UPDATE users
SET email = 'new@example.com'
WHERE id = 1;重点:修改和删除一定要带清楚 WHERE,否则可能影响很多行。
删除
DELETE FROM users WHERE id = 1;练习时可以直接删,正式业务里经常用“软删除”,也就是加一个 deleted_at 或 is_deleted 字段,而不是马上物理删除。
分页和排序
SELECT id, username
FROM users
ORDER BY id DESC
LIMIT 20 OFFSET 0;对应接口里常见的:
GET /users?page=1&page_size=206. 索引是什么
索引像书的目录。
没有索引时,数据库可能要一行一行找:
SELECT * FROM users WHERE username = 'tom';如果 username 上有索引,数据库能更快定位。
但索引不是越多越好:
- 查询会更快
- 写入可能变慢一点
- 索引也占空间
初学阶段记住:经常用来查询、排序、关联的字段,才值得考虑索引。
7. 事务是什么
事务就是“几步操作要么一起成功,要么一起失败”。
比如下单:
扣库存
创建订单
记录支付流水如果库存扣了,但订单创建失败,就会很麻烦。
事务保证:
全部成功 -> 提交 commit
中间失败 -> 回滚 rollback在 SQLAlchemy 里,你会经常看到:
try:
db.add(user)
await db.commit()
except Exception:
await db.rollback()
raise这就是在保护数据库状态。
8. SQL 和 ORM 怎么对应
| SQL 概念 | SQLAlchemy 里常见写法 | 大白话 |
|---|---|---|
| 表 | class User(Base) | 用 Python 类描述表 |
| 列 | mapped_column(...) | 用类属性描述字段 |
| 查询 | select(User) | 生成 SELECT |
| 条件 | .where(User.id == 1) | 生成 WHERE |
| 新增 | db.add(user) | 生成 INSERT |
| 提交 | await db.commit() | 保存变更 |
| 回滚 | await db.rollback() | 撤销本次失败操作 |
你可以先把 ORM 当成“Python 风格的 SQL 生成器”。等项目复杂后,再深入学习关系加载、性能优化和事务边界。
9. 常见错误
| 问题 | 原因 | 解决 |
|---|---|---|
| 不知道该建几张表 | 把所有字段塞一张表 | 先按业务对象拆表,比如用户、文章、订单 |
| 修改数据影响太多行 | UPDATE 忘了 WHERE | 修改和删除前先确认条件 |
| 用户名重复报错 | 唯一约束生效 | 捕获冲突并返回 409 |
| 查询变慢 | 没索引或一次查太多 | 加合适索引,接口分页 |
| 数据只成功一半 | 没理解事务 | 关键流程用 commit/rollback |
| 把 ORM 当黑盒 | 不知道背后 SQL | 学会看日志里的 SQL |
10. 学习顺序
建议按这个顺序来:
- 先会画出业务表:用户表、文章表、订单表。
- 再会写最常用 SQL:
SELECT、INSERT、UPDATE、DELETE。 - 再理解主键、唯一约束、外键。
- 再理解索引和事务。
- 最后进入 SQLAlchemy CRUD。
总结表
| 名词 | 大白话 |
|---|---|
| 数据库 | 保存长期数据的资料室 |
| 表 | 同一类数据的表格 |
| 行 | 一条具体数据 |
| 列 | 数据的一个字段 |
| 主键 | 每行数据的身份证 |
| 外键 | 一张表指向另一张表的关联字段 |
| SQL | 操作数据库的标准语言 |
| 索引 | 帮数据库快速查找的目录 |
| 事务 | 几步数据库操作要么全成,要么全撤 |
| ORM | 用代码对象操作数据库的工具 |
下一篇建议:大白话讲解——FastAPI 连接数据库并实现增删改查。