Schema Migration 是在应用程序开发过程中对数据库结构变化进行版本化管理的过程。每个更改都通过脚本描述,并依次应用于 dev、staging 和 production 环境。根据 JetBrains(2025)的数据,78% 的团队使用架构迁移工具,而 34% 仍通过控制台手动修改数据库——这是架构差异的主要来源。迁移自动化消除了人为因素,并保证了环境之间结构的一致性。
要点
Schema Migration 是通过版本化文件管理数据库结构变化的实践,这些文件依次应用于不同环境。每个文件包含一组 SQL 命令:创建表、添加列、更改索引或更新约束。迁移工具跟踪已应用的版本,并保证每个更改恰好执行一次。
与迁移表内容的 Data Migration 不同,Schema Migration 只管理结构——DDL 操作。这是根本区别:Schema Migration 在 Data Migration 之前运行,创建目标架构,然后 Data Migration 用数据填充它。根据 Redgate(2024)的数据,生产数据库中 62% 的事件与没有迁移脚本的手动架构更改有关。
每个 Schema Migration 都获得一个唯一标识符——通常是版本(V1、V2)或时间戳。该工具在特殊表(flyway_schema_history、alembic_version)中存储已应用迁移的列表。启动时,它将列表与 classpath 中的文件进行比较,并仅应用新的迁移。幂等性是关键特性:重新运行不会产生副作用。
典型的 Schema Migration 操作:创建表(CREATE TABLE)、添加列(ALTER TABLE ADD COLUMN)、更改类型、创建索引、添加外键和更新序列。更复杂的迁移包括保留数据的同时重命名列、将表拆分为多个部分以及将架构复制到分片。
如果没有 Schema Migration,开发人员会手动修改数据库——在控制台中编写 DDL,在 dev 环境中添加列,然后凭记忆将其复制到 staging。结果:环境之间的架构差异、部署时更改丢失以及生产环境中迁移损坏。Schema Migration 解决了三个关键问题:一致性、可再现性和审计。
当数据库结构在代码中描述时,它在 dev、staging 和 production 中是相同的。开发人员无法忘记应用更改——该工具将依次执行所有遗漏的迁移。如果生产环境中缺少某列,但代码需要它——应用程序将出错崩溃。自动检查消除了这种情况。
团队新成员运行 flyway migrate 命令,并在几秒钟内获得当前架构——无需生产环境转储和手动 DDL 查询。这在使用微服务架构时尤为重要,因为每个服务都有自己的数据库,架构由数十个迁移组成。完全可再现性将入职时间从几天缩短到几分钟。
每个 Schema Migration 都存储在版本控制系统中,与应用程序代码一起。您可以打开 Pull Request,查看架构更改的精确 SQL 命令,并执行代码审查。发生事件时,可以轻松确定最后一个应用的迁移及其作者。Git 历史记录提供项目整个生命周期中数据库更改的完整轨迹。
市场上有数十种适用于不同语言和平台的 Schema Migration 工具。选择取决于技术栈、迁移描述格式和回滚要求。让我们看看主要类别和流行工具。
| 工具 | 语言 | 格式 | 回滚 |
|---|---|---|---|
| Flyway | Java、Kotlin、Scala | SQL、Java | 通过单独脚本 |
| Liquibase | Java、Groovy、Kotlin | XML、YAML、JSON、SQL | 内置回滚 |
| Alembic | Python | Python、SQL | 自动生成降级 |
| Active Record | Ruby | Ruby DSL | 通过还原 |
| Entity Framework | C# | C# Fluent API | 自动生成 |
对于 Java/Kotlin 技术栈 — Flyway 是最轻量级和最可预测的工具。对于需要频繁回滚的项目 — Liquibase,其架构内置了回滚功能。对于 Python/Django — Alembic 是 SQLAlchemy 的标准工具。对于没有 DevOps 工程师的初创公司 — 选择配置最少的工具:Flyway 只需要一个脚本文件和 migrate 命令。
除了开源工具之外,还有商业解决方案:Redgate SQL Change Automation、Datical DB 和 DBmaestro。它们提供可视化架构比较、自动冲突解决和 CI/CD 管道集成。然而,对于大多数项目,Flyway 或 Alembic 无需额外许可证即可覆盖 100% 的需求。
让我们看看 Kotlin 中使用 Flyway 进行 Schema Migration 的实际示例。让我们创建一个将 orders 表添加到 PostgreSQL 数据库的迁移。Flyway 会自动创建 flyway_schema_history 表并跟踪应用的版本。
-- V1__Create_Orders_Table.sql
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
total_amount DECIMAL(10,2) NOT NULL,
currency VARCHAR(3) NOT NULL DEFAULT 'USD',
status VARCHAR(20) NOT NULL DEFAULT 'pending',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id)
);
通过 dataSource 配置在 Kotlin 项目中连接 Flyway。配置后,flyway:migrate 命令将应用 classpath 中的所有新迁移。
// FlywayConfig.kt — Spring Boot 中的 Flyway 配置
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.flywaydb.core.Flyway
@Configuration
class FlywayConfig {
@Bean
fun flyway(dataSource: DataSource): Flyway {
return Flyway.configure()
.dataSource(dataSource)
.locations("classpath:db/migration")
.baselineOnMigrate(true)
.load()
}
}
Alembic 是用于 Python 的 Schema Migration 工具,构建在 SQLAlchemy 之上。其主要特性是基于 SQLAlchemy 模型与当前数据库架构的比较自动生成脚本。Alembic 适用于 Django、FastAPI 和 Flask 项目。
初始化(alembic init alembic)和配置连接字符串后,alembic revision --autogenerate 命令扫描 SQLAlchemy 模型并生成迁移脚本。开发人员只需检查生成的代码并通过 alembic upgrade head 应用它。Autogenerate 节省了手动编写 DDL 的时间。
# models.py — 用于自动生成的 SQLAlchemy 模型
from sqlalchemy import Column, Integer, String, DateTime, Enum
from sqlalchemy.orm import DeclarativeBase
import enum
class OrderStatus(enum.Enum):
pending = "pending"
paid = "paid"
shipped = "shipped"
class Base(DeclarativeBase):
pass
class Order(Base):
__tablename__ = "orders"
id = Column(Integer, primary_key=True)
status = Column(Enum(OrderStatus), nullable=False)
created_at = Column(DateTime, nullable=False)
经验丰富的团队制定了一套 Schema Migration 规则,可降低故障风险并简化调试。遵循这些实践是成熟工程文化的标志。五个关键规则涵盖迁移的设计、测试和部署。
每个 Schema Migration 应只进行一次逻辑更改:创建表、添加列或更改索引。在单个迁移中混合多个操作会使回滚复杂化——如果第二个操作失败,第一个操作已应用且需要单独回滚。小步走是可靠迁移的基础。
迁移应用到生产环境后,不能修改——只能创建修复问题的新迁移。编辑已发布的迁移会破坏跟踪器:拥有不同数据库的开发人员将看到哈希不匹配。不可变迁移可保证在所有环境中具有可预测的行为。
在生产环境中应用 Schema Migration 之前,在生产数据副本上执行它。目的是检查执行速度、表锁定情况和更改的正确性。对于大型表,ALTER TABLE 可能会阻塞写入数小时——测试将提前发现这一点。Staging 环境配合生产转储是强制步骤。
没有默认值的 NOT NULL 新列是迁移失败的常见原因。在现有记录中,值将为 NULL,而 NOT NULL 会导致错误。最佳实践:创建具有默认值和 nullable 的列,然后在数据填充后通过单独的迁移添加 NOT NULL。
常见问题
Schema Migration 管理数据库结构(表、列、索引),Data Migration 管理内容(行、文档)。Schema Migration 始终首先执行,创建目标架构,然后 Data Migration 用数据填充它。工具不同:Flyway 用于架构,ETL 用于数据。
对于 Java/Kotlin — Flyway 是最简单和最快速的。对于 Python — Alembic,与 SQLAlchemy 集成。对于 .NET — Entity Framework Migrations。对于多语言项目 — Liquibase 具有独立的描述格式。
Flyway 不支持自动回滚 — 需要编写单独的取消脚本。Liquibase 自动为 XML/YAML 格式生成回滚。Alembic 为每次迁移创建降级函数。不可变方法用新迁移代替回滚是现代化实践。
该工具将迁移标记为失败。数据库保持在其应用之前的状态(如果没有自动提交)。需要在新迁移中修复错误并重新运行。绝不编辑失败的迁移——创建新的迁移。
对于生产项目——是的。Git 之外的手动 DDL 更改会导致架构差异、部署损坏和数据丢失。即使对于 MVP,也要使用最小工具——例如,带有几个 SQL 脚本的 Flyway。这在首次部署到 staging 时就会得到回报。
总结
NOT NULL。我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。