gorm支持复合主键,需显式为每个参与字段标注primarykey标签,整型字段须加autoincrement:false禁用自增;automigrate仅首次建表生效,修改主键需清表重迁或手动建约束;crud操作必须提供全部主键字段值。

GORM 支持复合主键,但必须显式声明所有参与字段为 primaryKey,且不能依赖默认的 AutoIncrement 行为——整型字段需手动关闭自增,否则迁移会失败或产生意外行为。
定义结构体时必须同时标注多个 primaryKey 标签
复合主键不是“选一个主键再加唯一约束”,而是把多个字段共同设为主键。GORM v2 要求每个字段都带上 primaryKey tag,缺一不可:
type Product struct {
ID string `gorm:"primaryKey"`
LanguageCode string `gorm:"primaryKey"`
Code string
Name string
}
若用整型字段(如 uint64),默认会触发 AUTO_INCREMENT,但复合主键不允许单字段自增。必须显式禁用:
CategoryID uint64 `gorm:"primaryKey;autoIncrement:false"`TypeID uint64 `gorm:"primaryKey;autoIncrement:false"`
迁移时不会自动创建主键约束?检查 AutoMigrate 是否生效
GORM 的 AutoMigrate 只在首次建表时应用主键定义;如果表已存在,它不会修改主键结构。常见错误是改了 struct tag 但没删表重迁,导致数据库实际无复合主键。
- 开发阶段建议用
db.Migrator().DropTable(&Product{})清理后重试 - 生产环境切勿直接
AutoMigrate修改主键,应手写 SQL 或用Migrator().CreateConstraint补充(注意 MySQL/PostgreSQL 语法差异) - 验证是否成功:连接数据库执行
SHOW CREATE TABLE products,确认PRIMARY KEY (id, language_code)
查询、更新、删除时必须提供全部主键字段值
GORM 的 First、Take、Save、Delete 等方法依赖主键定位记录。若只传部分主键字段,GORM 会生成不完整 WHERE 条件,可能命中多行或零行:
- ✅ 正确:
db.First(&prod, map[string]interface{}{"ID": "p1", "LanguageCode": "zh-CN"}) - ❌ 错误:
db.First(&prod, "ID = ?", "p1")—— 缺少LanguageCode,GORM 不知道该查哪条 - ⚠️ 注意:
Save对已有记录是 UPDATE,但若结构体中主键字段为零值(如空字符串、0),GORM 会当成新记录 INSERT,触发主键冲突
复合主键本身不难写,难的是后续所有 CRUD 都得带着全套主键字段操作——漏一个,逻辑就断在数据库层,而且错误提示往往只是 “record not found” 或 “duplicate key”,不容易联想到主键定义问题。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











