第 14 课:使用 SQLModel + Alembic 初始化和升级数据库
第四阶段 · 真实 student-management-api · 面向 Docker 初学者
本课完成标准
你能够:
- 解释 SQLModel、SQLModel.metadata 和 Alembic 的关系;
- 检查 migrations/env.py;
- 生成并人工审查迁移文件;
- 在 ECS 容器中执行 alembic upgrade head;
- 验证 alembic_version;
- 理解为什么不使用 create_all() 代替正式迁移。
1. 三个对象的关系
SQLModel 模型(models/*.py)
│ metadata
▼
Alembic 迁移文件(migrations/versions/*.py)
│ upgrade
▼
宝塔 MySQL(实际表和数据)
| 对象 | 小白解释 | 本项目位置 |
|---|---|---|
| SQLModel 类 | 用 Python 类描述表、字段和关系 | models/student.py 等 |
| SQLModel.metadata | 收集所有模型的表结构信息 | 由 Alembic 读取 |
| revision | 一次结构变化的脚本 | migrations/versions/ |
| upgrade head | 把数据库升级到最新迁移 | 执行在 ECS 容器中 |
| alembic_version | 数据库记录当前迁移版本 | MySQL 中的版本表 |
2. 检查当前项目的 env.py
你的 migrations/env.py 已经做了三件关键事情:
from models import Student, Grade, Score, User
target_metadata = SQLModel.metadata
DB_HOST = os.getenv("DB_HOST", "127.0.0.1")
DB_PORT = os.getenv("DB_PORT", "3306")
DB_USER = os.getenv("DB_USER")
DB_PASSWORD = os.getenv("DB_PASSWORD")
DB_NAME = os.getenv("DB_NAME")
它会:
- 导入模型,让模型注册到 metadata;
- 把 SQLModel.metadata 交给 Alembic 自动比较;
- 从环境变量构造 MySQL 连接。
**注意:**如果忘记导入模型,--autogenerate 可能看不到新表,生成空迁移或错误迁移。
3. create_all() 和 Alembic 的区别
| 方式 | 作用 | 生产建议 |
|---|---|---|
| SQLModel.metadata.create_all(engine) | 按当前模型尝试创建不存在的表 | 适合临时开发,不记录结构变化 |
| Alembic migration | 记录新增字段、改名、索引等变化 | 生产环境使用,文件进入 Git |
当前 database.py 里有 create_db_and_tables()。正式生产不要依赖它来代替迁移,否则数据库无法知道从哪个版本升级到哪个版本。
4. 在开发环境生成迁移
修改 SQLModel 模型后,在本地开发环境或专用迁移环境执行:
# macOS
cd /Users/andy/Documents/code/student-management-api
source venv/bin/activate
# Windows PowerShell 使用对应的 venv 激活方式
alembic current
alembic revision --autogenerate -m "add student fields"
命令会在 migrations/versions/ 生成新的 Python 文件。不要直接把自动生成结果当成正确答案。打开新文件检查:
git diff -- migrations/versions
sed -n '1,240p' migrations/versions/新生成的文件.py
| 检查项 | 要问自己的问题 |
|---|---|
| upgrade() | 新增或修改的表、字段、索引是否正确? |
| downgrade() | 回退时是否会误删重要数据? |
| 表名和列名 | 是否把重命名误判为“删除 + 新增”? |
| 默认值和可空 | 已有数据能否满足新的非空字段? |
**自动生成只是助手。**它可能无法正确理解字段重命名、数据迁移和复杂约束,必须人工审查。
5. 提交迁移文件
git status
git add migrations/versions/修改后的迁移文件.py
git commit -m "feat: add database migration"
git push origin main
迁移文件是代码的一部分,必须和模型变化一起进入 GitHub。不要只在 ECS 上临时修改迁移脚本。
6. 在 ECS 容器中查看当前版本
cd /www/wwwroot/student-management-api
git pull --ff-only
docker compose config
docker compose ps
查看 Alembic 当前版本:
docker compose run --rm api alembic current
docker compose run --rm api alembic heads
current 显示数据库已经应用到哪里;heads 显示代码中最新迁移头。两者不同,说明数据库需要升级。
7. 执行初始化或升级
确认已经备份数据库,并确认 DB_HOST、用户权限和网络连接都通过第 13 课测试后,再执行:
docker compose run --rm api alembic upgrade head
也可以在正在运行的 API 容器中执行:
docker compose exec api alembic upgrade head
执行后确认:
docker compose run --rm api alembic current
docker compose logs --tail=100 api
run --rm 会临时创建一个使用同一镜像和 .env 的容器,迁移完成后自动删除,不会改变长期运行的 API 容器。
8. 在 MySQL 中确认结果
可以使用宝塔数据库管理或 MySQL 客户端查看:
SHOW TABLES;
SELECT version_num FROM alembic_version;
重点检查表、字段和索引是否符合迁移文件。不要只看命令显示成功,还要确认数据库实际结构。
9. 迁移失败时怎么办?
| 现象 | 先做什么 | 不要做什么 |
|---|---|---|
| Access denied | 检查 .env、用户授权和 Host | 不要改用 root |
| Can't connect | 重做第 13 课 TCP 测试 | 不要开放公网 3306 |
| Table already exists | 确认历史数据库和版本表 | 不要直接删生产表 |
| 字段误删/误改 | 停止发布,备份并人工修正迁移 | 不要盲目执行 downgrade |
alembic downgrade -1 只适合经过备份和验证的回退场景;MySQL 某些 DDL 不一定像普通事务一样可完全回滚。
10. 一分钟自测
问题 1:SQLModel.metadata 的作用是什么?
- A. 收集模型表结构,供 Alembic 比较
- B. 保存 MySQL 密码
- C. 启动 Nginx
问题 2:生产数据库升级通常执行什么命令?
- A. docker compose run --rm api alembic upgrade head
- B. 删除 migrations/
- C. 每次启动都执行 create_all()
答案:1A,2A。
本课通关证据
docker compose run --rm api alembic current
docker compose run --rm api alembic heads
docker compose run --rm api alembic upgrade head
docker compose run --rm api alembic current
完成标准:迁移文件已提交 GitHub;容器能连接宝塔 MySQL;upgrade head 成功;MySQL 中存在 alembic_version 且版本与 head 一致。
如果遇到迁移错误,请贴完整输出,但隐藏密码、Token 和私钥。
参考:Alembic 官方文档。
想系统学习这门课程?
你已阅读完本文。需要更完整的知识体系,可以继续了解「Vibe Coding 实战课程」。
查看课程详情