Rust 数据库迁移实战:用 sqlx 做版本化迁移与种子数据

test12026-10-2420 次阅读

迁移不该靠手敲 SQL

表结构演进最怕"开发库跑过、生产库没跑"。sqlx 提供编译期校验查询的 migrate 机制,把每一版 schema 变成带序号的文件,启动时自动按序执行,谁的环境漏了迁移都会立刻报错。

组织迁移文件

在 migrations/ 下放带时间戳前缀的 SQL,up 是正向变更,down 用于回滚。

-- migrations/20261024000000_create_users.up.sql
CREATE TABLE users (
    id BIGSERIAL PRIMARY KEY,
    email TEXT NOT NULL UNIQUE,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- migrations/20261024000000_create_users.down.sql
DROP TABLE users;

启动时自动执行迁移

用 sqlx::migrate! 在程序启动阶段把全部 pending 迁移跑完,失败直接 panic 阻止带病启动。

use sqlx::postgres::PgPoolOptions;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let pool = PgPoolOptions::new()
        .max_connections(8)
        .connect(&std::env::var("DATABASE_URL")?)
        .await?;

    sqlx::migrate!("./migrations").run(&pool).await?;
    println!("迁移完成,服务启动");
    Ok(())
}

用嵌入迁移做离线校验

sqlx::query! 宏会在编译期连库校验 SQL 字段,配合 migrate 文件能保证"代码里的查询"和"库里的表"永远对得上。种子数据也可以写成一个迁移:

-- migrations/20261024000100_seed_admin.up.sql
INSERT INTO users (email) VALUES ('admin@example.com')
ON CONFLICT (email) DO NOTHING;

这样新同事 clone 代码、起一个空库、跑服务,表结构和初始数据一次到位,不再有"在我机器上是好的"。

T

test1

文章作者

迁移不该靠手敲 SQL 表结构演进最怕"开发库跑过、生产库没跑"。sqlx 提供编译期校验查询的 migrate 机制...

分类
技术
发布时间
2026-10-24
字数
约 1104 字
阅读
20 次