You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无需CLI,通过代码执行Diesel数据库迁移遇问题求助

解决Actix Web + Diesel代码执行迁移无效果的问题

核心问题分析

你的代码存在几个关键问题导致迁移未执行:

  1. 嵌入迁移路径错误:embed_migrations! 应该指向整个migrations目录,而非单个迁移文件,否则Diesel无法扫描到待执行的迁移任务。
  2. 错误处理过于粗暴:unwrap()和expect()会掩盖潜在的加载/连接错误,导致你看不到问题根源。
  3. Docker构建上下文缺失:如果未将migrations目录复制到构建镜像的上下文,嵌入的迁移文件会不存在,自然无法执行。

修复步骤

1. 修正迁移嵌入代码

将单个迁移文件路径改为整个migrations目录,同时改进错误处理:

use diesel::{r2d2::ConnectionManager, r2d2::Pool};
use dotenvy::dotenv;
use diesel::pg::PgConnection;
use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
use std::error::Error;

#[derive(Clone)]
pub struct DbPoolManager {
    pub pool: Pool<ConnectionManager<PgConnection>>,
}

impl DbPoolManager {
    pub fn new() -> Self {
        dotenv().ok();
        let db_user = std::env::var("PG_USER").expect("PG_USER is not set");
        let db_password = std::env::var("PG_PASSWORD").expect("PG_PASSWORD is not set");
        let db_ip = std::env::var("PG_HOST").expect("PG_HOST is not set!");
        let db_name = std::env::var("PG_DBNAME").expect("PG_DBNAME is not set!");
        let connection_string = format!(
            "postgres://{}:{}@{}/{}",
            db_user, db_password, db_ip, db_name
        );

        let manager = ConnectionManager::<PgConnection>::new(connection_string);
        let pool = Pool::builder()
            .max_size(5)
            .build(manager)
            .expect("Failed to create postgres pool");
        DbPoolManager { pool }
    }

    pub fn run_migration(&self) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
        // 绑定到整个migrations目录,而非单个文件
        const MIGRATIONS: EmbeddedMigrations = embed_migrations!("../migrations/");
        
        // 保留连接实例直到迁移完成,避免提前归还池
        let mut conn = self.pool.get()?;
        let executed_migrations = conn.run_pending_migrations(MIGRATIONS)?;
        
        // 打印迁移日志,确认执行状态
        println!("Executed {} pending migrations", executed_migrations.len());
        Ok(())
    }
}

2. 验证依赖配置

确保Cargo.toml中diesel_migrations启用了postgres特性:

[dependencies]
diesel = { version = "2.0", features = ["postgres", "r2d2", "dotenv"] }
diesel_migrations = { version = "2.0", features = ["postgres"] }
r2d2 = "0.8"
dotenvy = "0.15"
actix-web = "4"

3. 修正Docker构建逻辑

在Dockerfile中添加migrations目录的复制步骤,确保构建上下文包含迁移文件:

# 构建阶段
FROM rust:1.70 as builder
WORKDIR /app
COPY Cargo.toml Cargo.lock ./
COPY src ./src
COPY migrations ./migrations  # 必须复制此目录,否则嵌入迁移失效
RUN cargo build --release

# 运行阶段
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends libpq5 && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=builder /app/target/release/your-app-binary .
CMD ["./your-app-binary"]

4. 确保数据库就绪

如果使用Docker Compose,添加healthcheck确保数据库完全启动后再启动应用:

services:
  db:
    image: postgres:15
    environment:
      POSTGRES_USER: your-user
      POSTGRES_PASSWORD: your-pass
      POSTGRES_DB: your-db
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U your-user -d your-db"]
      interval: 5s
      timeout: 5s
      retries: 5
  app:
    build: .
    depends_on:
      db:
        condition: service_healthy
    environment:
      PG_USER: your-user
      PG_PASSWORD: your-pass
      PG_HOST: db
      PG_DBNAME: your-db

额外验证

运行应用后,可以登录数据库查询schema_migrations表,确认迁移记录是否存在:

SELECT * FROM schema_migrations;

内容的提问来源于stack exchange,提问作者RfDzDeveloper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 09:17:02