数据库迁移
问题
Python 项目中如何做数据库迁移管理?Alembic 和 Django Migration 有什么区别?
答案
Alembic(SQLAlchemy 配套)
Alembic 是 SQLAlchemy 官方的迁移工具:
# 初始化
alembic init migrations
# 自动生成迁移脚本(对比模型和数据库差异)
alembic revision --autogenerate -m "add users table"
# 执行迁移
alembic upgrade head
# 回滚
alembic downgrade -1
生成的迁移文件:
migrations/versions/001_add_users_table.py
def upgrade():
op.create_table(
"users",
sa.Column("id", sa.Integer(), primary_key=True),
sa.Column("name", sa.String(50), nullable=False),
sa.Column("email", sa.String(120), unique=True),
)
op.create_index("ix_users_email", "users", ["email"])
def downgrade():
op.drop_index("ix_users_email")
op.drop_table("users")
Django Migrations
Django 内置迁移系统,与 ORM 深度集成:
# 生成迁移文件
python manage.py makemigrations
# 执行迁移
python manage.py migrate
# 查看待执行的迁移
python manage.py showmigrations
# 回滚到指定迁移
python manage.py migrate myapp 0003
对比
| 特性 | Alembic | Django Migrations |
|---|---|---|
| 绑定框架 | SQLAlchemy | Django |
| 自动检测 | --autogenerate | makemigrations |
| 版本管理 | 线性链 + 分支 | 有向无环图(DAG) |
| 数据迁移 | op.execute() | RunPython |
| 合并迁移 | alembic merge | squashmigrations |
数据迁移(Data Migration)
结构迁移之外,还需要迁移数据:
# Alembic 数据迁移
def upgrade():
# 先加字段
op.add_column("users", sa.Column("full_name", sa.String(100)))
# 再迁移数据
op.execute("UPDATE users SET full_name = first_name || ' ' || last_name")
# 最后删旧字段
op.drop_column("users", "first_name")
op.drop_column("users", "last_name")
常见面试问题
Q1: 迁移冲突怎么处理?
答案:
团队协作时,两人同时创建迁移会产生分支。解决方案:
- Alembic:
alembic merge -m "merge heads"创建合并迁移 - Django:
python manage.py makemigrations --merge
Q2: 生产环境如何安全执行迁移?
答案:
- 先在 staging 环境测试迁移脚本
- 备份数据库后再执行
- 大表加字段使用
ALTER TABLE ... ADD COLUMN ... DEFAULT NULL(避免锁表) - 拆分迁移:结构变更和数据迁移分开执行
- 确保迁移脚本有
downgrade(可回滚)
Q3: 如何做零停机迁移?
答案:
以"重命名字段"为例,需拆成多步:
- 添加新字段 → 部署代码(同时写新旧字段)
- 数据迁移(旧 → 新)
- 部署代码(只读新字段)
- 删除旧字段