Files
xuanzhi-service/server/.ai-transition/remake/gorm-auto-migrate-and-upgrade-sql.md
wdh-home 1e33640629
Some checks failed
CI / init (pull_request) Has been cancelled
CI / Frontend node 18.16.0 (pull_request) Has been cancelled
CI / Backend go (1.22) (pull_request) Has been cancelled
CI / release-pr (pull_request) Has been cancelled
CI / devops-test (1.22, 18.16.0) (pull_request) Has been cancelled
CI / release-please (pull_request) Has been cancelled
CI / devops-prod (1.22, 18.x) (pull_request) Has been cancelled
CI / docker (pull_request) Has been cancelled
基础项目
2026-04-26 15:32:21 +08:00

5.3 KiB
Raw Blame History

GORM 自动迁移与升级 SQL 交接说明

背景

  • 当前服务启动时会执行 main.go -> initialize.RegisterTables() -> initialize.bizModel()
  • initialize/gorm_biz.go 中注册了 book 业务模型,并调用 db.AutoMigrate(...)
  • 因此即使没有手动执行 .sql 文件,只要服务启动并连接到数据库,book 相关业务表也可能被 GORM 自动创建。

AutoMigrate 的信息来源

  • GORM 不读取 .ai-specs/doc-sql/*.sql 中的基线 SQL。
  • 表名来自各模型的 TableName()
  • 字段名来自 Go struct 字段名的 snake_case 映射。
  • 字段类型、默认值、非空、索引、唯一索引、注释主要来自 gorm tag。
  • 基础字段来自模型嵌入结构,例如 model/book/base.goHardDeleteModel

示例:

Title string `gorm:"type:varchar(255);not null;comment:书名主标题"`
BookType string `gorm:"type:varchar(64);not null;index;comment:书籍类型字典值,对应 book_type"`
Rating float64 `gorm:"type:numeric(3,1);not null;default:0.0;comment:书籍评分,范围 0-10"`

AutoMigrate 能做什么

  • 新表不存在时,按 Model 创建表。
  • 新字段不存在时,通常会补充字段。
  • 新索引不存在时,通常会尝试创建索引。
  • 部分字段类型、默认值、注释可能会按数据库驱动能力尝试调整。

AutoMigrate 不能当作升级 SQL

  • 它不知道旧版本到新版本的业务升级意图。
  • 它不会可靠删除废弃字段。
  • 它不会可靠删除废弃索引。
  • 字段重命名通常会被识别为新增字段,旧字段仍保留。
  • 字段类型收缩、非空约束、唯一约束、CHECK 约束、历史数据回填等需要人工判断。
  • 它不能保证生产升级顺序、幂等性、兼容性和数据安全。

结论:AutoMigrate 是开发期快速补结构工具,不是正式数据库版本迁移方案。

升级 SQL 维护规则

  • 修改 .ai-specs/doc-sql/*.sql 并导致表结构、字段、索引、约束、默认值或注释变化时,必须同步维护升级 SQL。
  • 修改 .ai-specs/doc-dict/*.md 并导致系统字典主数据或字典项变化时,必须同步维护初始化数据和升级 SQL。
  • 升级 SQL 固定放在 .ai-transition/database-upgrade-doc
  • 当前版本号以 .ai-specs/sys-specs/database-upgrade-doc-spec.md当前数据库表结构版本 为准。
  • 当前为 v1 时,兼容变更写入 .ai-transition/database-upgrade-doc/v1.sql
  • 升级 SQL 只写从既有数据库升级到当前目标结构的变更,不重复粘贴完整建表 SQL。
  • 同一次业务变更涉及多张表时,写入同一个当前版本 SQL 文件,并按表分组。
  • 字典主数据升级按 sys_dictionaries.type 防重复。
  • 字典明细升级按 sys_dictionary_details.sys_dictionary_id + value 防重复。
  • 固定值域字典需要写 sys_dictionariessys_dictionary_details;动态值域字典默认只写 sys_dictionaries
  • 字典升级 SQL 禁止裸 INSERT,必须兼容重复执行、手工已建数据和部分明细缺失。
  • 字典升级 SQL 命中已软删数据时,恢复启用数据必须同步置空 deleted_at

常见变更处理

  • 新增字段:写 ALTER TABLE ... ADD COLUMN ...,并补 COMMENT ON COLUMN
  • 新增 NOT NULL 字段:先给默认值或先回填历史数据,再追加 NOT NULL
  • 修改字段类型:先评估历史数据是否兼容,再写 ALTER TABLE ... ALTER COLUMN ... TYPE ...
  • 删除字段:必须人工确认无业务读写依赖,再写 ALTER TABLE ... DROP COLUMN IF EXISTS ...
  • 新增普通索引:写 CREATE INDEX IF NOT EXISTS idx_<table>_<field> ...
  • 删除索引:写 DROP INDEX IF EXISTS ...
  • 新增唯一索引:先排查历史重复数据,必要时先清洗,再创建唯一索引。
  • 修改字段名:优先写 ALTER TABLE ... RENAME COLUMN ...,不要依赖 GORM 自动识别。
  • 修改注释:写 COMMENT ON TABLECOMMENT ON COLUMN
  • 新增固定值域字典:同步修改 source/system/dictionary.gosource/system/dictionary_detail.go 和当前版本 SQL。
  • 新增动态值域字典:同步修改 source/system/dictionary.go 和当前版本 SQL没有固定值项时不改 dictionary_detail.go
  • 修改固定字典项展示信息:升级 SQL 先 UPDATE 已有 value,再 INSERT 缺失项。
  • 废弃固定字典项:优先将 status 改为 false,不要直接删除历史值项。

配置建议

  • 开发环境可以保留 config.yamlsystem.disable-auto-migrate: false,便于快速补表。
  • 生产或正式联调环境建议设置 system.disable-auto-migrate: true,统一使用 .ai-transition/database-upgrade-doc/*.sql 做可审计升级。
  • 如果生产环境仍开启 AutoMigrate,必须接受它可能自动补字段或索引、但不会完整处理删除和复杂变更的风险。

交接检查清单

  • 已确认 .ai-specs/doc-sql/*.sql 是目标结构说明,不会被程序自动执行。
  • 已确认真实自动建表入口是 initialize/gorm_biz.goAutoMigrate
  • 已确认 Model 的 gorm tag 是 AutoMigrate 生成 DDL 的主要依据。
  • 已确认结构升级 SQL 需要人工维护,不能指望 GORM 生成。
  • 已确认生产环境是否关闭自动迁移,并形成团队约定。