无需CLI,通过代码执行Diesel数据库迁移遇问题求助
解决Actix Web + Diesel代码执行迁移无效果的问题
核心问题分析
你的代码存在几个关键问题导致迁移未执行:
- 嵌入迁移路径错误:
embed_migrations!应该指向整个migrations目录,而非单个迁移文件,否则Diesel无法扫描到待执行的迁移任务。 - 错误处理过于粗暴:
unwrap()和expect()会掩盖潜在的加载/连接错误,导致你看不到问题根源。 - 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
相关产品推荐
相关产品推荐

