Buffalo 的 buffalo db migrate 仅支持向前迁移,不内置回滚功能;需用 -v 指定版本并配对 .down.sql 文件才能降级,否则静默跳过。

buffalo db migrate 会直接执行所有待迁移文件,不支持按版本回退
Buffalo 的 buffalo db migrate 命令本质是调用 pop(Buffalo 默认 ORM)的 migrate 命令,它只做「向前迁移」:扫描 migrations/ 目录下所有未执行的 .sql 或 .go 文件,按文件名前缀时间戳顺序执行。它没有内置的 down 或 rollback 子命令——哪怕你写了 Down 函数,buffalo db migrate 也不会调用它。
常见错误现象:buffalo db migrate 执行后发现逻辑有误,想退回上一版,但执行 buffalo db migrate --help 看不到 rollback 选项;手动改数据库再重跑迁移,结果下次 buffalo db migrate 又报 “already applied” 冲突。
- 真正可用的回退方式只有两个:
buffalo db migrate -v <version>(指定目标版本号,需已存在对应down实现)或手动执行 SQL 回滚 -
version指的是 migration 文件名开头的时间戳,例如20240512103022_create_users.up.sql的 version 是20240512103022 - 必须确保该 version 对应的
.down.sql文件存在,且内容正确;pop 不校验 down 脚本是否真能逆向操作 - 企业级场景中,建议把每个
.up.sql都配对写好.down.sql,并加入 CI 检查:diffup和down是否构成可逆操作
pop 迁移脚本里 up/down 必须成对定义,否则 -v 降级会静默失败
Pop 的迁移引擎要求:如果要用 buffalo db migrate -v 20240512103022 降级到某个版本,它会查找同名的 .down.sql(或 .down.go),然后执行。但若该文件不存在,pop 不报错、不中断,而是跳过——最终状态停留在原版本,你以为“降级成功”,其实什么都没发生。
使用场景:CI 流水线中自动执行迁移回滚验证,或本地调试时快速切版本。
- 检查迁移文件是否成对:
ls migrations/*up.sql | sed 's/\.up\.sql$/.down.sql/' | xargs -I {} sh -c '[ -f {} ] || echo "MISSING: {}"' -
.down.sql不能只是DROP TABLE,要考虑外键、索引、默认值等副作用;比如up加了唯一约束,down就得先删约束再删列 - Go 类型迁移(
.up.go)中,Down函数签名必须与Up一致,且返回 error;pop 不做运行时类型校验,写错会导致迁移命令无提示退出
database.yml 中 pool 和 idle_timeout 必须显式配置,否则迁移可能卡死
Buffalo 自动生成的 database.yml 在开发环境常省略连接池参数,导致 buffalo db migrate 在高并发或长事务迁移(如大数据量 UPDATE)时,因连接耗尽而 hang 住,日志只显示 “waiting for connection”,无具体错误。
性能影响:默认 pop 使用 pool: 5,但迁移脚本本身不释放连接直到整个 migrate 命令结束;如果某条 SQL 执行超 3 分钟,而 idle_timeout 是默认 0(永不超时),连接池会被占满,后续 migrate 或应用启动全阻塞。
- 生产 database.yml 至少要设:
pool: 20、idle_timeout: 60(单位秒)、max_open_connections: 30 - 迁移过程不涉及应用业务逻辑,建议单独配一个高 pool 值的 profile,例如
migration:段,避免影响线上服务连接池 - 执行迁移前加健康检查:
buffalo db migrate --dry-run不真正执行,只输出将运行哪些文件,适合放入部署前校验环节
buffalo db migrate 的 exit code 不可靠,不能直接用于自动化判断成败
Pop 的迁移命令在部分失败场景下仍返回 0,比如:某条 up.sql 执行出错(如语法错误),但前面几条已提交,pop 会打印错误日志但 exit code 还是 0。CI 脚本若只靠 $? == 0 判断,就会误认为迁移成功。
容易踩的坑:Kubernetes InitContainer 里用 buffalo db migrate 做 schema 初始化,因 exit code 误判导致 Pod 启动失败却没被发现。
- 必须配合日志关键字检测:
buffalo db migrate 2>&1 | grep -q "FATAL\|ERROR\|failed",有就 exit 1 - 更稳妥做法:用
pop migrate status先查当前状态,再用pop migrate up(来自 pop CLI,非 buffalo 封装)并捕获真实 exit code - 所有迁移操作建议包装成 grift 任务,例如
grift migrate:to[20240512103022],便于统一控制输出和退出行为
CREATE TABLE IF NOT EXISTS 是必须的,而 INSERT INTO config VALUES (...) 就得加 ON CONFLICT DO NOTHING,否则二次迁移必然失败。


















