beego 的 bee migrate 仅执行手动编写的 sql 迁移脚本,依赖文件名时间戳排序和 migration.register() 注册机制,不自动建模、不维护状态表、不支持 orm 方法,且跨数据库兼容性差。

Beego 的 bee migrate 不是自动建模工具,它只执行你写的 SQL,也不维护状态表——所有迁移是否执行过,全靠文件名里的时间戳和本地 database/migrations/ 目录下已注册的结构体是否被调用过。
生成迁移文件时必须用 bee generate migration,不能手建
手动创建 .go 文件容易漏掉 init() 中的 migration.Register() 调用,导致 bee migrate 完全看不到这个迁移。生成命令会自动写好包名、结构体命名规则(含时间戳)、Created 字段和注册逻辑:
-
bee generate migration add_status_to_orders会在database/migrations/下生成类似20260821_111533_add_status_to_orders.go的文件 - 文件名中的时间戳是 Beego 判断执行顺序的唯一依据,不能改;结构体名如
AddStatusToOrders_20260821_111533也必须与文件名一致,否则注册失败 - 如果项目还没初始化
database/migrations/目录,bee不会自动创建,需先手动建好
Up() 和 Down() 里只能写原生 SQL,不支持 ORM 方法
Beego 迁移不解析模型定义,也不调用 orm 包,Up() 和 Down() 内部只能用 m.SQL("...") 执行语句。常见陷阱包括:
- MySQL 中添加非空字段没设默认值会报错:
m.SQL("ALTER TABLE users ADD COLUMN phone VARCHAR(20) NOT NULL")→ 必须加DEFAULT ''或先允许 NULL -
Down()不是Up()的逆操作自动生成,要人工写,比如Up()加字段,Down()就得用DROP COLUMN;删表的话,Down()得重建表结构(不含数据) - 跨数据库兼容性差:SQLite 不支持
DROP COLUMN,PostgreSQL 对字段重命名要用RENAME COLUMN,而 MySQL 是CHANGE COLUMN—— 迁移脚本一旦写死,就只能锁定一种 DB
执行 bee migrate 前必须确认当前环境配置正确
bee migrate 默认读取 conf/app.conf 中的数据库配置,但不会校验连接是否可用。常因以下原因静默失败或连错库:
- 没设置
runmode,它会用dev模式,但如果你的app.conf里只有[prod]段,就会连不上 -
db配置项名必须是db(不是database或mysql),且格式为driver://user:pass@tcp(host:port)/dbname?charset=utf8mb4 - 执行时若提示
no migration files found,大概率是database/migrations/不在main包路径下,或该目录没被go build包含(比如放在了models/下)
bee migrate rollback 只回退最后一次,且不可跳步
Beego 不记录已执行迁移的完整历史,rollback 实际只是按时间戳倒序找最后一个已执行的迁移,调用其 Down()。这意味着:
- 不能指定回退到某版本,比如
bee migrate rollback -n 2是无效的 - 如果中间某个
Down()报错(如字段已被其他迁移删掉),后续迁移也不会继续回退,流程中断 - 执行
rollback后再migrate,会重新执行刚刚回退的那个迁移(因为时间戳还在),不会跳过
真正关键的不是命令会不会跑,而是每个 m.SQL() 是否在目标环境上验证过——本地 SQLite 跑通的语句,上线到 MySQL 可能因语法或权限直接失败。迁移前务必在同构环境做一次完整 Up + Down 测试,别信“应该没问题”。











