跳到主要内容

第 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 官方文档。


← 第 13 课:连接宝塔 MySQL · 第 15 课:验证真实项目 →

课程推荐

想系统学习这门课程?

你已阅读完本文。需要更完整的知识体系,可以继续了解「Vibe Coding 实战课程」。

查看课程详情