20260513-Alembic

10 阅读3分钟

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 headalembic downgrade -1),计算出需要迁移到的版本ID
    • 遍历迁移脚本:run_migrations()会扫描versions/目录下的所有迁移脚本,根据它们的down_revision/revision构建成一条依赖链,从当前版本触发,沿着链走到目标版本
    • 按顺序收集需要执行迁移的脚本,然后依次执行对应的upgrade()downgrade()函数

基于模型自动生成迁移脚本

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文件中定义数据库的最终期望状态