💻

database-migration

👤 ҉Breeze🌔 📦 v1.0.0 ⭐ 4.4 ⬇️ 172 下载
💻 开发编程 免费

📖 技能介绍


name: database-migration slug: "database-migration" version: "1.0.0" displayName: "database-migration" summary: "使用 Alembic、Prisma Migrate、Flyway 和 Knex 等工具创建、执行和回滚版本化数据库模式迁移。" description: 使用 Alembic、Prisma Migrate、Flyway 和 Knex 等工具创建、执行和回滚版本化数据库模式迁移。 license: MIT metadata: author: AI Agent Skills Community version: 1.0.0


Database Migration

该技能使 AI agent 能够通过迁移框架管理版本化的数据库模式变更。agent 创建向前和向后迁移脚本,处理模式变更期间的数据填充,确保使用安全的迁移模式实现零停机部署,并将迁移工作流集成到 CI/CD 流水线中。它支持的主要工具包括 Alembic(Python/SQLAlchemy)、Prisma Migrate(TypeScript/Node)、Flyway(Java/SQL)和 Knex(JavaScript)。

Workflow

  1. 评估模式变更: 分析请求的变更——添加列、创建表、修改约束、重命名字段或转换数据。将变更分类为向后兼容(新增)或破坏性(删除),以确定部署策略。破坏性变更需要采用多阶段迁移方法。

  2. 选择迁移工具: 根据项目的技术栈选择合适的迁移框架。对于 Python/SQLAlchemy 项目使用 Alembic,对于 TypeScript/Prisma 项目使用 Prisma Migrate,对于 Java 或 SQL-first 工作流使用 Flyway,对于 Node.js/Express 项目使用 Knex。确保该工具已初始化并连接到目标数据库。

  3. 生成迁移脚本: 在支持的场景下自动生成迁移脚本(Alembic autogenerate、Prisma migrate dev),然后审查并编辑生成的脚本。添加显式的回滚(降级)逻辑。对于数据填充,将数据转换包含在迁移中以保持模式和数据变更的一致性。

  4. 在预发环境中测试: 在镜像生产环境的预发数据库上应用迁移。验证迁移是否干净应用、现有查询仍可运行,并且回滚能恢复到之前状态。使用迁移后的模式运行应用程序的测试套件。

  5. 使用零停机策略部署: 对于生产环境,使用扩展与收缩迁移。第一阶段:添加新列/表(扩展),不删除旧结构。第二阶段:部署写入旧和新结构的应用程序代码。第三阶段:填充数据。第四阶段:部署仅使用新结构的代码。第五阶段:移除旧列/表(收缩)。这确保了无停机并可在每个阶段安全回滚。

    小葱技能站7w4.net发现了升级插件。

  6. 验证与监控: 部署后,使用框架的状态命令验证迁移状态。监控应用程序日志和数据库性能以检测回归问题。确认所有迁移元数据都记录在框架的版本表中。

支持的技术

  • Alembic: Python、SQLAlchemy、PostgreSQL/MySQL/SQLite
  • Prisma Migrate: TypeScript/JavaScript、Prisma ORM、PostgreSQL/MySQL/SQLite/SQL Server
  • Flyway: Java、基于 SQL 的迁移、所有主流 RDBMS
  • Knex: JavaScript/TypeScript、Node.js、PostgreSQL/MySQL/SQLite
  • Django Migrations: Python、Django ORM
  • Sequelize: JavaScript、Node.js ORM

Usage

描述你需要的模式变更(例如,“在 users 表中添加 phone_number 列”)并指定项目使用的迁移框架。agent 将生成包含升级和降级逻辑的迁移文件,提供应用方法,并就生产环境的安全部署策略提供建议。

Examples

示例 1:Alembic 迁移 —— 添加列并填充数据

请求: 在 users 表中添加 display_name 列,并通过连接 first_name 和 last_name 填充该列。

生成迁移:

alembic revision --autogenerate -m "add_display_name_to_users"

迁移文件(versions/20250115_add_display_name_to_users.py):

"""add display_name to users

Revision ID: a1b2c3d4e5f6
Revises: 9z8y7x6w5v4u
Create Date: 2025-01-15 10:30:00.000000
"""
from alembic import op
import sqlalchemy as sa

revision = "a1b2c3d4e5f6"
down_revision = "9z8y7x6w5v4u"
branch_labels = None
depends_on = None


def upgrade():
    # Phase 1: Add the column as nullable (safe, no locks on reads)
    op.add_column("users", sa.Column("display_name", sa.String(300), nullable=True))

    # Phase 2: Backfill existing rows
    users = sa.table(
        "users",
        sa.column("id", sa.Integer),
        sa.column("first_name", sa.String),
        sa.column("last_name", sa.String),
        sa.column("display_name", sa.String),
    )
    op.execute(
        users.update().values(
            display_name=sa.func.concat(
                users.c.first_name, " ", users.c.last_name
            )
        )
    )

    # Phase 3: Set NOT NULL after backfill is complete
    op.alter_column("users", "display_name", nullable=False)


def downgrade():
    op.drop_column("users", "display_name")

应用并验证:

alembic upgrade head
alembic current   # Confirms: a1b2c3d4e5f6 (head)

示例 2:Prisma Migrate —— 添加 Reviews 模型

请求: 在 Prisma 项目中添加一个与 User 和 Product 关联的 Review 模型。

更新 prisma/schema.prisma

model Review {
  id        Int      @id @default(autoincrement())
  rating    Int      @db.SmallInt
  comment   String?  @db.Text
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  userId    Int
  productId Int
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  product   Product  @relation(fields: [productId], references: [id], onDelete: Cascade)

  @@unique([userId, productId])
  @@index([productId])
  @@index([rating])
}

生成并应用迁移:

npx prisma migrate dev --name add_reviews_table

生成的 SQL(prisma/migrations/20250115_add_reviews_table/migration.sql):

CREATE TABLE "Review" (
    "id" SERIAL NOT NULL,
    "rating" SMALLINT NOT NULL,
    "comment" TEXT,
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updatedAt" TIMESTAMP(3) NOT NULL,
    "userId" INTEGER NOT NULL,
    "productId" INTEGER NOT NULL,
    CONSTRAINT "Review_pkey" PRIMARY KEY ("id")
);

CREATE INDEX "Review_productId_idx" ON "Review"("productId");
CREATE INDEX "Review_rating_idx" ON "Review"("rating");
CREATE UNIQUE INDEX "Review_userId_productId_key" ON "Review"("userId", "productId");
ALTER TABLE "Review" ADD CONSTRAINT "Review_userId_fkey"
    FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE;
ALTER TABLE "Review" ADD CONSTRAINT "Review_productId_fkey"
    FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE CASCADE;

最佳实践

  • 始终为每次迁移编写显式的降级/回滚逻辑,以便在部署出现问题时可以安全回滚。永远不要假设在压力下能手动撤销迁移。
  • 使迁移向后兼容,通过扩展与收缩的方式:先添加新结构,再迁移数据,最后在新代码完全部署后再单独迁移移除旧结构。
  • 不要在未审查的情况下运行自动生成的迁移 —— 自动检测工具在遇到重命名字段时可能会生成破坏性操作(如删除列)。始终检查生成的 SQL。
  • 在支持的环境中对 DDL 使用事务(PostgreSQL 会将 DDL 包含在事务中;MySQL 不支持)。对于不支持事务的 DDL 数据库,需规划部分失败恢复方案。
  • 保持迁移小而聚焦 —— 每个迁移文件对应一个逻辑变更。这使回滚更精细,并更容易识别导致问题的迁移。
  • 在 CI 中运行迁移,针对一次性数据库以在进入生产前捕获错误。测试中应包含升级和降级路径。

Edge Cases

  • 大表迁移: 在拥有数百万行数据的表中添加带有默认值的 NOT NULL 列,在旧版 PostgreSQL 中可能会锁表几分钟。使用 ADD COLUMN ... DEFAULT ... NOT NULL(PostgreSQL 11+ 无锁)或先设为可空,分批填充数据,再设置 NOT NULL。
  • 列重命名: 大多数迁移工具将重命名视为删除 + 添加,会导致数据丢失。在 Alembic 中使用 op.alter_column() 或使用原始的 ALTER TABLE ... RENAME COLUMN 执行真正的重命名。应用前验证生成的迁移。
  • 并发迁移: 在多实例部署中,确保只有一个实例运行迁移。使用咨询锁(Flyway 和 Alembic 支持)或在部署流水线中将迁移作为专用步骤,在推出应用程序实例之前执行。
  • 枚举类型变更: 向 PostgreSQL 枚举添加值是非事务性的。创建新枚举类型,迁移列,然后删除旧类型。或者使用带 CHECK 约束的 VARCHAR 以方便修改。
  • 仅数据迁移: 当你需要转换数据但不改变模式时(例如加密某列的值),仍应使用迁移文件以确保其在不同环境中可版本化和重现。

🤖 AI 评测

这个数据库迁移技能质量较好,工作流程清晰完整,涵盖了主流迁移工具的使用方法和最佳实践。优点是内容全面、示例丰富,特别是零停机部署策略和边界情况处理很有价值。不足之处是缺少独立的示例文件和配置文件,资源配套相对单薄。对于需要管理数据库迁移的开发者来说,这是一个实用的参考技能。

📊 多维度评分

适应性4.3
规范性4.4
有效性4.6
可靠性4
可信度4.9

📁 包含文件 (3 个)

📄 SKILL.md 8.6 KB
📄 _meta.json 137 B
📄 _skillhub_meta.json 144 B