gorm.model提供预置id、createdat、updatedat、deletedat字段及默认标签,适合多数场景;自定义主键类型或列名需手动声明字段并加gorm:"primarykey"或gorm:"column:xxx"标签,混用会导致主键冲突。

GORM 模型定义不是“写完结构体就完事”,字段标签(gorm:"...")才是控制数据库行为的关键开关——漏写、错写或顺序混乱,轻则迁移失败,重则数据写入被静默忽略。
gorm.Model 和手写 ID 字段的区别在哪
用 gorm.Model 是最省心的起点:它自动带 ID uint、CreatedAt、UpdatedAt、DeletedAt 四个字段,并默认配置好主键、时间戳和软删除逻辑。但如果你需要自定义主键类型(比如 string 或 uuid.UUID),就不能嵌入 gorm.Model,得手动声明字段并加 gorm:"primaryKey" 标签。
常见错误是混用:type User struct { gorm.Model ID string `gorm:"primaryKey"` } —— 这会导致两个 ID 字段冲突,GORM 会报 duplicated primary key 错误。
- 要继承默认时间戳和软删除?用
gorm.Model,别自己重复定义CreatedAt等字段 - 要自定义主键类型或名称?去掉
gorm.Model,手动写字段 +gorm:"primaryKey" - 想禁用软删除?删掉
DeletedAt字段,或显式加gorm:"softDelete:false"(GORM v1.25+)
column、type、size 这三个标签谁优先级更高
column 控制列名映射,type 控制底层 SQL 类型(如 type:varchar(255)),size 是 type 的快捷写法(等价于 type:varchar(255) 对应 size:255)。三者不冲突,但要注意:
-
type会完全覆盖 GORM 默认推导的类型,包括长度;size只影响长度,不改类型基底(比如size:50对string就是varchar(50),但对[]byte就是blob或longblob,取决于实际长度) - MySQL 中
type:text和size:65535效果不同:前者是标准 TEXT,后者可能被转成varchar(65535),超出限制直接报错 -
column不影响类型,只改名字;但名字变了,索引、外键等依赖列名的功能就得同步更新
not null、default、 权限标签怎么配合用
not null 是 DDL 层约束,影响建表语句;default 是插入时无值情况下的填充值(SQL 层 default,不是 Go 层零值);而 或 <code>->:false 是运行时行为开关,决定 GORM 是否在 INSERT/UPDATE 或 SELECT 中包含该字段。
-
Email string `gorm:"not null;default:'unknown@example.com'"`→ 建表加NOT NULL DEFAULT 'unknown@example.com',且插入时不传Email也能成功 -
PasswordHash []byte `gorm:":false"`→ 创建时写入,查询时永远不读(防止意外暴露) -
UpdatedAt time.Time `gorm:"autoUpdateTime"`本质是+ 自动赋值,不需要再写 <code>default或not null - 注意:
default值必须是数据库能解析的字面量(如'now()'、123),不能是 Go 表达式(time.Now()无效)
foreignkey 和 many2many 标签为什么总配不对
外键关系失效,90% 是因为字段名没对齐。GORM 不靠命名约定自动推导,必须显式声明 foreignKey(本模型字段名)和 joinForeignKey/joinReferences(关联表字段名)。
例如用户-角色多对多:
type User struct {
gorm.Model
Name string
Roles []Role `gorm:"many2many:user_roles;joinForeignKey:UserID;joinReferences:RoleID"`
}
type Role struct {
gorm.Model
Name string
}
这里 joinForeignKey:UserID 指的是关联表 user_roles 里存 User ID 的字段名,不是 User 模型里的字段名(User 模型里没有 UserID 字段,只有 ID)——所以这个写法是错的。正确写法是:
- 要么让关联表字段名匹配模型字段名(推荐):
joinForeignKey:ID(对应 User.ID),joinReferences:ID(对应 Role.ID) - 要么在 User 模型里显式加一个
UserID uint字段,并设gorm:"primaryKey;autoIncrement:false",再指向它 -
many2many表名必须全小写、下划线分隔;如果用了驼峰(如UserRoles),GORM 会生成错误的表名user_rol_es
最易忽略的一点:关联字段的类型必须和被引用主键类型严格一致(uint 对 uint,string 对 string),否则 AutoMigrate 会跳过建外键,也不报错。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











