Skip to main content

Command Palette

Search for a command to run...

Alembic 数据库迁移 101

Updated
•3 min read•View as Markdown
Alembic 数据库迁移 101
L

I am a developer working in BGI located in Shenzhen. I am familiar with genomics 🧬 and coding. I love 🏀 👩🏻‍💻 and Hiphop🎵

这篇教程带你轻松入门 Alembic。我们将一起探索:

  • 🤔 为什么需要 Alembic? 它解决了什么痛点?

  • 🤝 Alembic 与数据库(例如 SQLite)的关系是什么?

  • ⚙️ alembic upgrade head 这句“咒语”究竟是如何工作的?

  • 🚀 一个从零开始的实战演练

准备好了吗?让我们开始吧!


🤔 为什么要用 Alembic?想象一下这个场景…

你正在开发一个很酷的应用,并且使用 SQLAlchemy 作为 ORM (Object-Relational Mapper) 来操作你的数据库。最初,你的用户模型(User model)可能长这样:

Python

# models.py
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    username = Column(String(50), nullable=False)
    email = Column(String(120), unique=True, nullable=False)

项目进展顺利,你的数据库里已经有了一些用户数据。突然,产品经理跑过来说:“我们需要给用户添加一个 bio(简介)字段!”

你该怎么办?

  1. 直接手动修改数据库? 🙅‍♀️ 这样做非常危险!如果你在生产环境的数据库上操作失误,可能会导致数据丢失。而且,团队里的其他开发者怎么知道数据库结构变了?他们本地的数据库还是旧的,代码更新后一跑就报错。

  2. 在代码里改 User 模型,然后呢? 🤔 你可以在 User 类里加上 bio = Column(String(300)),但这并不会自动在数据库里添加对应的列。你需要一种方法来告诉数据库:“嘿,我们的模型变了,你也得跟着变!”

这就是 Alembic 登场的时刻! ✨

Alembic 是一个数据库迁移 (database migration) 工具。你可以把它想象成数据库结构的 "Git"。它能够:

  • 版本化你的数据库结构:每一次对数据库结构的变更(比如添加一个新表或新字段),Alembic 都会生成一个“迁移脚本”。

  • 可靠地更新:你可以在任何地方(你的电脑、同事的电脑、生产服务器)运行这些脚本,确保数据库结构和你的代码保持同步。

  • 轻松回滚:如果新的变更出了问题,Alembic 可以帮你安全地“降级”回之前的版本。

简而言之:Alembic 让你能够用写代码的方式,系统、安全、可追溯地管理数据库结构的演进。


🤝 Alembic, SQLAlchemy 和数据库的关系

要理解 Alembic,首先要明白它在技术栈中的位置。

  • 数据库 (例如 SQLite, PostgreSQL): 这是最终存储数据的地方。它只懂 SQL 语言。

  • SQLAlchemy: 这是一个 ORM,它扮演着“翻译官”的角色。它让你用 Python 对象 (classes) 来定义数据模型,然后把这些模型“翻译”成数据库能懂的 SQL 语句,帮你执行增删改查等操作。

  • Alembic: 它建立在 SQLAlchemy 之上,专门负责结构变更。Alembic 会比较你的 SQLAlchemy 模型和当前数据库的真实状态,然后自动生成那些 ALTER TABLE, CREATE TABLE 等 SQL 语句,并把它们打包成一个个版本化的迁移脚本。

它们的关系就像这样:

你的应用代码 💻
      |
      v
SQLAlchemy (定义模型) 📝
      |
      v
Alembic (比较模型与数据库,生成迁移脚本) 📜
      |
      v
数据库 (SQLite, PostgreSQL, etc.) 💾

对于 SQLite 来说,Alembic 完全支持。不过 SQLite 有一些自身的限制(比如不太支持 ALTER 一些复杂的东西),Alembic 很聪明地提供了“批处理模式”(batch mode) 来解决这些问题,它会创建一个新表,把旧数据导过去,再删掉旧表,对你来说这个过程是无感的。


🚀 Alembic 101 实战演练

说了这么多理论,让我们来亲手实践一下吧!我们将从一个空项目开始,使用 SQLite 和 Alembic。

步骤 1: 安装必要的库

Bash

pip install sqlalchemy alembic

步骤 2: 初始化 Alembic 环境

在你的项目根目录下,运行这个命令:

Bash

alembic init alembic

这个命令会创建一个 alembic 文件夹和一个 alembic.ini 配置文件。

  • alembic.ini: 这是 Alembic 的主配置文件。

  • alembic/env.py: 这是 Alembic 运行时会执行的脚本,用来配置数据库连接和读取你的模型。

  • alembic/versions/: 这个文件夹将来会存放所有的迁移脚本。

步骤 3: 配置 Alembic

首先,我们要告诉 Alembic 我们的数据库在哪里。打开 alembic.ini 文件,找到 sqlalchemy.url 这一行,把它修改成你的数据库连接字符串。对于 SQLite,可以这样写:

Ini, TOML

# alembic.ini
sqlalchemy.url = sqlite:///mydatabase.db

接下来,我们要让 Alembic 知道我们的 SQLAlchemy 模型在哪里。打开 alembic/env.py,找到 target_metadata = None 这一行。我们需要把它指向我们模型的 Base.metadata。

假设你的模型都定义在 models.py 文件里,就像我们最开始的例子一样。你需要:

  1. 在 env.py 的顶部导入你的模型 Base。

  2. 将 target_metadata 设置为 Base.metadata。

Python

# alembic/env.py

# 加上这句导入
from models import Base
...

# ... 其他代码 ...
...

# 修改这一行
# target_metadata = None
target_metadata = Base.metadata

💡 提示: 为了让这个导入能工作,你可能需要在你的项目根目录下运行 alembic 命令。

步骤 4: 创建你的第一个迁移

现在,我们的 models.py 里已经有了一个 User 模型。让我们运行 Alembic 的自动生成命令,来创建第一个迁移脚本。

Bash

alembic revision --autogenerate -m "Create users table"
  • revision: 创建一个新的迁移版本。

  • --autogenerate: 告诉 Alembic 自动检测模型和数据库的差异,并生成迁移代码。

  • -m "...": 为这次迁移添加一条简短的说明,就像 Git commit message。

执行成功后,你会发现在 alembic/versions/ 目录下多了一个新的 Python 文件,文件名类似 d412b545c99a_create_users_table.py。打开它看看:

Python

"""Create users table

Revision ID: d412b545c99a
Revises: 
Create Date: 2025-07-16 20:00:00.000000

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'd412b545c99a'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('users',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('username', sa.String(length=50), nullable=False),
    sa.Column('email', sa.String(length=120), nullable=False),
    sa.PrimaryKeyConstraint('id'),
    sa.UniqueConstraint('email')
    )
    # ### end Alembic commands ###


def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_table('users')
    # ### end Alembic commands ###

看到 upgrade() 和 downgrade() 函数了吗?

  • upgrade(): 定义了如何“前进”到这个版本(创建 users 表)。

  • downgrade(): 定义了如何“后退”回上一个版本(删除 users 表)。


⚙️ alembic upgrade head 的逻辑解析

到目前为止,我们只是生成了一个脚本,数据库本身还没有任何变化。现在,是时候执行它了!

输入这句“咒语”:

Bash

alembic upgrade head

让我们来拆解它:

  • alembic: 主命令。

  • upgrade: 一个动作,意思是“升级数据库”,即执行迁移脚本里的 upgrade() 函数。

  • head: 这是一个指针,指向最新的那个迁移版本。

所以,alembic upgrade head 的完整意思是:“把我的数据库升级到最新的版本!”

Alembic 会检查数据库里一个叫 alembic_version 的特殊表(如果不存在会自动创建),看看当前的版本号是什么。然后,它会按照顺序,一个接一个地执行所有它还没执行过的迁移脚本,直到 head 为止。

在这个例子里,因为是第一次,它会执行 d412b545c99a_create_users_table.py 里的 upgrade() 函数。执行完毕后,mydatabase.db 文件就会被创建,并且里面会有一张 users 表!

那么,如果我们又加了新字段呢?

现在,我们回到最初的问题,给 User 模型加上 bio 字段:

Python

# models.py (更新后)
class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    username = Column(String(50), nullable=False)
    email = Column(String(120), unique=True, nullable=False)
    bio = Column(String(300), nullable=True) # <-- 新增字段

我们再次运行自动生成命令:

Bash

alembic revision --autogenerate -m "Add bio column to users table"

Alembic 又会在 versions 文件夹里创建一个新的迁移文件,内容大概是这样:

Python

def upgrade():
    op.add_column('users', sa.Column('bio', sa.String(length=300), nullable=True))

def downgrade():
    op.drop_column('users', 'bio')

此时,head 指针已经移动到了这个最新的迁移版本。我们再次运行:

Bash

alembic upgrade head

Alembic 会发现数据库的版本是 d412b545c99a,而最新的 head 是刚刚生成的这个新版本。于是,它只会执行这个新的迁移脚本,为 users 表添加 bio 这一列。

如果想回滚呢?也很简单:

Bash

alembic downgrade -1

这会执行最新版本里的 downgrade() 函数,把 bio 字段删掉。


总结 🎉

恭喜你!你已经掌握了 Alembic 的核心逻辑。让我们来回顾一下:

  • Alembic 是数据库结构的 Git,它让你的数据库 schema 变更变得安全、可控、可追溯。

  • 它与 SQLAlchemy 紧密配合,自动根据你的 Python 模型生成迁移脚本。

  • alembic init 用来初始化环境。

  • alembic revision --autogenerate -m "..." 用来在你修改模型后创建新的迁移脚本。

  • alembic upgrade head 是你最常用的命令,用来将数据库更新到最新版本。

现在,alembic upgrade head 这句命令对你来说不再是神秘的“咒语”,而是你手中管理数据库演进的强大工具。希望这篇教程对你有帮助! Happy coding! 🚀

More from this blog

Mapping Human Society to K-Means and KNN.

在复杂多变的人类社会中,群体的形成与个体的归属是如此自然,以至于我们很少停下来思考其中的机制。而当我们将视角转向机器学习的世界,会惊讶地发现:算法与人类社会的运作模式有着惊人的相似之处。K-Means聚类与K最近邻(KNN)分类算法,不仅是数据科学的基础工具,更可作为理解人类社会复杂动态的隐喻镜像。 群体形成:K-Means聚类的社会演绎 想象一下,每个人都是多维空间中的一个数据点,我们的价值观、兴趣、文化背景等构成了这个空间的坐标轴。在这个"社会空间"中,K-Means算法的运作与群体形成过程...

Apr 7, 20252 min read
Mapping Human Society to K-Means and KNN.

Linux top command 101

🎉 欢迎来到 Linux top 命令的 101 教程! 🎉 大家好!我是你的系统性能超级英雄,top 命令!🚀 今天,我们将一起深入探索这个强大而又实用的工具,让你彻底掌握 top 命令的魔法!✨ 目标读者: 想要深入理解 Linux 系统性能监控,并希望通过 top 命令来排查问题、优化性能的你!无论你是 Linux 新手还是老鸟,相信你都能从这篇教程中有所收获!🎯 教程风格: 我们将采用 Andrej Karpathy 和 Hugging Face 风格,这意味着: 实战驱动: ...

Mar 24, 20258 min read
Linux top command 101
L

lewismessthecode

13 posts