直接用gorm.Model嵌入最省事,但需用标签手动控制字段名、主键和时间戳;自定义主键加gorm:"primaryKey",列名不一致用gorm:"column:xxx",忽略字段用gorm:"-",嵌入结构体用embeddedPrefix防冲突,时间字段注意类型与空值处理,字段名必须大写导出。

直接用 gorm.Model 嵌入是最省事的起点,但字段名、主键、时间戳行为不满足业务需求时,必须手动控制标签——别指望“默认”能覆盖所有场景。
用 gorm.Model 嵌入快速起步
它自带 ID、CreatedAt、UpdatedAt、DeletedAt 四个字段,类型和标签都已预设好,适合多数 CRUD 场景。
- 嵌入后无需重复声明这四个字段,避免手误写错类型或漏掉
gorm:"primaryKey" -
DeletedAt默认启用软删除,调用Delete时实际是更新该字段而非物理删除 - 如果表里没有
created_at或字段名是createtime,嵌入后仍需用标签覆盖:CreatedAt time.Time `gorm:"column:createtime"`
自定义主键和列名必须靠 gorm 标签
GORM 不会读取结构体字段注释或变量名大小写来推断数据库列名,一切以 gorm 标签为准。
- 主键不是
ID?必须显式加gorm:"primaryKey",比如UserID uint `gorm:"primaryKey"` - 列名和字段名不一致?必须用
gorm:"column:xxx",例如Username string `gorm:"column:username"` - 想跳过某个字段(如密码明文)不映射到数据库?加
gorm:"-",注意后面有空格,否则解析失败 - 字段名含下划线(如
user_name),GORM 默认转驼峰(UserName),但不会反向推导;必须用column显式指定
嵌入结构体时前缀控制容易被忽略
用 embedded 标签把子结构体字段“摊平”进父结构体很常见,但字段名冲突或需要区分来源时,embeddedPrefix 是关键。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 不加前缀:
Address struct{ City string } `gorm:"embedded"`→ 生成列city - 加前缀:
Address struct{ City string } `gorm:"embedded;embeddedPrefix:addr_"`→ 生成列addr_city - 两个嵌入结构体含同名字段(如都含
Name),不加前缀会导致编译报错或覆盖,必须用前缀隔离 -
embeddedPrefix只影响列名,不影响 Go 结构体内存布局或访问方式
时间字段类型与零值行为要对齐数据库
time.Time 在 GORM 中默认映射为 DATETIME,但 MySQL 的 DATETIME 不支持纳秒精度,PostgreSQL 的 TIMESTAMP WITH TIME ZONE 则支持——类型不匹配会丢精度或报错。
- MySQL 用户建议用
CreatedAt time.Time `gorm:"type:datetime"`明确类型,避免驱动自动选timestamp导致时区问题 - 字段可为空?用
*time.Time而非time.Time,否则零值0001-01-01 00:00:00 +0000 UTC写入数据库可能触发 NOT NULL 约束失败 - 想让
CreatedAt仅在创建时赋值、更新时不改?加gorm:"createOnly",否则默认每次Save都会刷新
最常被绕过的其实是字段可见性:所有模型字段必须是大写开头(即 exported),小写字段 GORM 直接忽略,连报错都不会有——查不到数据时先盯一眼首字母。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










