#数据库迁移工具 Alembic:版本化管理你的数据库表结构
📂 所属阶段:第三阶段 — 数据持久化(数据库篇)
🔗 相关章节:SQLAlchemy 2.0 实战 · 依赖注入系统
#1. Alembic 是什么?
#1.1 为什么需要 Alembic?
- 手动改表:
ALTER TABLE直接在生产数据库执行,无法回滚,风险极高 - Django migrate:耦合 Django,不适合 FastAPI 项目
- Alembic:轻量、灵活、与 SQLAlchemy 无缝集成,支持版本化、迁移、回滚
#1.2 安装与初始化
pip install alembic
cd your_project
alembic init alembic初始化后生成:
project/
├── alembic/
│ ├── env.py # 迁移环境配置
│ ├── script.py.mako # 迁移文件模板
│ └── versions/ # 迁移文件存放目录
├── alembic.ini # 配置文件
└── models.py # 你的模型定义#2. 配置 env.py
#2.1 基础配置
# alembic/env.py
from logging.config import fileConfig
from sqlalchemy import engine_from_config, pool
from alembic import context
# 导入你的模型(重要!Alembic 据此生成迁移脚本)
from models import Base # SQLAlchemy Base
from config import get_settings
config = context.config
settings = get_settings()
# 设置数据库 URL
config.set_main_option("sqlalchemy.url", settings.database_url)
if config.config_file_name is not None:
fileConfig(config.config_file_name)
target_metadata = Base.metadata
def run_migrations_offline() -> None:
"""离线模式:生成 SQL 脚本,不连接数据库"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online() -> None:
"""在线模式:直接连接数据库执行迁移"""
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(connection=connection, target_metadata=target_metadata)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()#3. 生成和运行迁移
#3.1 自动生成迁移
# 对比模型与当前数据库,自动生成迁移脚本
alembic revision --autogenerate -m "add user avatar column"
# 参数说明:
# --autogenerate:自动对比模型差异
# -m:添加迁移说明生成的迁移文件示例:
# alembic/versions/20260326_add_user_avatar.py
"""add user avatar column
Revision ID: abc123
Revises: def456
Create Date: 2026-03-26 14:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers
revision = 'abc123'
down_revision = 'def456'
branch_labels = None
depends_on = None
def upgrade() -> None:
op.add_column('users', sa.Column('avatar', sa.String(length=500), nullable=True))
def downgrade() -> None:
op.drop_column('users', 'avatar')#3.2 手动编写迁移
# 当 autogenerate 无法处理时,手动编写
def upgrade() -> None:
# 添加列
op.add_column("users", sa.Column("phone", sa.String(20)))
# 重命名列
op.alter_column("users", "name", new_column_name="display_name")
# 创建索引
op.create_index("ix_users_email", "users", ["email"], unique=True)
# 创建外键
op.create_foreign_key(
"fk_posts_author", "posts", "users", ["author_id"], ["id"]
)
def downgrade() -> None:
op.drop_column("users", "phone")
op.drop_index("ix_users_email", table_name="users")#3.3 应用迁移
# 查看迁移状态
alembic current
alembic history --verbose
# 升级到最新版本
alembic upgrade head
# 升级到指定版本
alembic upgrade abc123
# 升一级
alembic upgrade +1
# 回滚一级
alembic downgrade -1
# 回滚到初始版本
alembic downgrade base#4. 依赖链管理
#4.1 迁移文件依赖关系
base (初始)
├── 001_add_users.py
│ ↓
├── 002_add_posts.py
│ ↓
└── 003_add_comments.py
↓
head (最新)每个迁移文件的 down_revision 必须指向前一个版本:
# 003_add_comments.py
down_revision = "002_add_posts" # 指向 002
# 002_add_posts.py
down_revision = "001_add_users" # 指向 001
# 001_add_users.py
down_revision = None # 初始版本#4.2 合并分支(多条迁移链)
如果有两个开发分支合并:
# 迁移链 A: base → 001a → 002a
# 迁移链 B: base → 001b → 002b
# 合并后:
# base → 001a → 002a → 003_merge → 001b → 002b → head
# 或者合并到统一的主线#5. 多数据库配置
#5.1 不同环境的数据库连接
# config.py
import os
class Settings:
env = os.getenv("ENV", "development")
databases = {
"development": "postgresql+asyncpg://localhost:5432/myapp_dev",
"testing": "postgresql+asyncpg://localhost:5432/myapp_test",
"production": "postgresql+asyncpg://user:pass@db.example.com/myapp",
}
@property
def database_url(self):
return self.databases.get(self.env, self.databases["development"])# 不同环境运行迁移
ENV=development alembic upgrade head
ENV=production alembic upgrade head#6. 最佳实践
✅ 推荐
1. 始终使用 --autogenerate + 手动审核结合
2. 每个迁移文件只做一件事
3. 始终编写 downgrade() 方法
4. 在 CI/CD 中先在测试库跑迁移,确认无误再上生产
5. 禁止在生产环境使用 alembic upgrade head,用 --sql 模式审核后再执行
6. 多人开发:每次拉代码后先 alembic upgrade head
❌ 避免
1. 不要手动修改已提交到 Git 的迁移文件
2. 不要在迁移中对数据进行不可逆操作
3. 不要跳过版本号#7. 小结
| 命令 | 说明 |
|---|---|
alembic init alembic | 初始化 |
alembic revision -m "说明" | 创建空迁移 |
alembic revision --autogenerate -m "说明" | 自动生成迁移 |
alembic upgrade head | 升级到最新 |
alembic downgrade -1 | 回滚一级 |
alembic history | 查看迁移历史 |
alembic current | 查看当前版本 |
💡 安全迁移原则:生产环境的每次迁移都应该先在本地测试库验证,生成 SQL 审核无误后再执行。DBA 审核 > 直接在线上执行。
🔗 扩展阅读

