Alembic
管理数据库结构的git
初始化
alembic init alembic
执行后,会生成:
alembic.ini:Alembic的主配置文件,需要按照自己的项目修改正确的数据库连接地址等参数alembic/:迁移脚本的核心目录versions/:存放各个版本的迁移脚本env.py:核心配置文件,定义如何连接数据库和加载模型script.py.mako:生成新迁移脚本的模版文件
env.py
作用:运行时执行的引擎
- 建立连接
- 加载模型元数据
- 执行migration
- 设置target_metadata(让Alembic知道模型的结构):导入自己的SQLAlchemy Base类,设置
target_metadata=Base.metadata - 设置项目根目录
import sys
from pathlib import Path
PROJECT_ROOT=Path(__file__).resolve().parent[1]
if str(PROJECT_ROOT) not in sys.path:
sys.path.insrt(0,str(PROJECT_ROOT))
- 动态获取数据库URL
resolved_database_url = resolve_database_url(config.get_main_option("sqlalchemy.url"))
config.set_main_option("sqlalchemy.url", resolved_database_url)
- env.py中会有
run_migrations_offline/run_migrations_online的标准结构 - 创建引擎
engine = engine_from_config(
config.get_section(config.config_ini_section), # 加载配置
prefix='sqlalchemy.',
poolclass=pool.NullPool # 指定使用的连接池,常见的包括QueuePool, NullPool, SingletonThreadPool, StaticPool. 迁移脚本一般是一次性运行的短期任务常用NullPool
)
- 运行调度迁移任务
context.run_migrations()- 读取版本表:Alembic会在目标数据库创建一张表(默认为
alembic_version,仅一列version_num,用来记录当前数据库的版本),记录当前易用的迁移版本号 - 确定目标版本:根据命令行参数(如
alembic upgrade head或alembic downgrade -1),计算出需要迁移到的版本ID - 遍历迁移脚本:
run_migrations()会扫描versions/目录下的所有迁移脚本,根据它们的down_revision/revision构建成一条依赖链,从当前版本触发,沿着链走到目标版本 - 按顺序收集需要执行迁移的脚本,然后依次执行对应的
upgrade()或downgrade()函数
- 读取版本表:Alembic会在目标数据库创建一张表(默认为
基于模型自动生成迁移脚本
alembic revision --autogeneate -m "xxx"
对比当前模型和数据库真实状态,自动生成变更代码。(复杂的变更仍需手动检查和修改) 代码中会包含upgrade和downgrade两个函数
alembic upgrade head # 将数据库升级到最新状态
alembic downgrade -1 # 将数据库回滚到上一个版本
script.py.mako
迁移脚本的生成器,一个模版文件,当运行alemic revision生成新脚本是,Alembic按照这个模版生成新的.py文件
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
from __future__ import annotations
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}
def upgrade() -> None:
${upgrades if upgrades else "pass"}
def downgrade() -> None:
${downgrades if downgrades else "pass"}
各数据库迁移工具对比
| 特征 | 🔧 应用专属 (Alembic) | 📜 语言无关 (Flyway/Liquibase) | 🗺️ 声明式 (Atlas) |
|---|---|---|---|
| 核心理念 | 模型即真相 (Model as source of truth) | 脚本即真相 (Script as source of truth) | 期望状态即真相 (Desired state as source of truth) |
| 依赖程度 | 高度依赖特定技术栈 (SQLAlchemy) | 完全独立,与语言和框架无关 | 相对独立,但依赖其特定配置 |
| 迁移生成 | 自动生成基础框架,可手动修改 | 完全手动编写 | 完全自动计算和生成 |
| 最佳场景 | Python 项目,特别是使用 SQLAlchemy 的项目 | 任何语言/项目,团队习惯纯 SQL 版本控制 | 大规模、多环境、安全审查严格的项目 |
- 使用python和SQLAlchemy,Alembic最适配
- Flyway可以按文件名顺序执行
.sql文件,语言无关性 - Liquibase,除了SQL,还可以用XML、YAML或JSON来描述变更
- Atlas,声明式工作流,在HCL或SQL文件中定义数据库的最终期望状态