Alembic 数据库迁移 101

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(简介)字段!”
你该怎么办?
直接手动修改数据库? 🙅♀️ 这样做非常危险!如果你在生产环境的数据库上操作失误,可能会导致数据丢失。而且,团队里的其他开发者怎么知道数据库结构变了?他们本地的数据库还是旧的,代码更新后一跑就报错。
在代码里改
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 文件里,就像我们最开始的例子一样。你需要:
在
env.py的顶部导入你的模型Base。将
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! 🚀



