🔐 1. 字段级权限控制:不是所有字段都能随便改!
GORM 默认允许对结构体所有导出字段进行读写,但有时你希望某些字段“只读”、“只写”甚至“假装不存在”。
type User struct {
ID uint
Name string `gorm:"<-:create"` // 只能创建时写入(如用户名)
Password string `gorm:"->:false;<-:create"` // 创建时写入,但不能从 DB 读回(安全!)
UpdatedAt time.Time `gorm:"->"` // 只读(自动更新时间,禁止手动改)
Internal string `gorm:"-"` // 完全忽略(不参与任何 DB 操作)
}
💡 小贴士:
gorm:"-"是调试神器,临时加个字段不影响表结构!
⏱️ 2. 自动时间戳:支持 Unix 秒/毫秒/纳秒!
GORM 默认用 CreatedAt / UpdatedAt 字段记录时间,但你也可以自定义类型:
type Event struct {
CreatedAt time.Time // 标准 time.Time
Updated int64 `gorm:"autoUpdateTime:nano"` // 纳秒时间戳
Created int64 `gorm:"autoCreateTime"` // 秒级时间戳
}
✅ 适用场景:IoT 设备上报、日志系统、高性能事件流——省去
time.Now().Unix()手动赋值!
🧩 3. 嵌入结构体:让模型更干净
匿名嵌入(常用):
type User struct {
gorm.Model // 自动包含 ID, CreatedAt, UpdatedAt, DeletedAt
Name string
}
命名嵌入 + 前缀:
type Author struct {
Name string
Email string
}
type Blog struct {
ID int
Author Author `gorm:"embedded;embeddedPrefix:author_"`
}
// 数据库字段:author_name, author_email
🧠 优势:避免重复定义,同时保持数据库字段清晰命名。
🤝 4. 关联创建:一键保存主从数据
type User struct {
gorm.Model
Name string
CreditCard CreditCard
}
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
// 自动创建 User 和 CreditCard
db.Create(&User{
Name: "jinzhu",
CreditCard: CreditCard{Number: "4111..."},
})
⚠️ 注意:如果不想保存关联,用
Omit:
db.Omit("CreditCard").Create(&user)
db.Omit(clause.Associations).Create(&user) // 跳过所有关联
🛠️ 5. Upsert(冲突处理):存在就更新,不存在就插入
GORM 支持跨数据库的 ON CONFLICT / ON DUPLICATE KEY:
// 存在 id 冲突时,更新 name 和 age
db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
DoUpdates: clause.AssignmentColumns([]string{"name", "age"}),
}).Create(&users)
✅ 适用场景:用户注册去重、配置同步、缓存预热。
🎯 6. Smart Select:只查你需要的字段
大模型?别怕!用 Find 直接映射到精简结构体:
type User struct {
ID uint
Name string
Age int
Email string
// ... 100 个字段
}
type APIUser struct {
ID uint
Name string
}
var users []APIUser
db.Model(&User{}).Limit(10).Find(&users)
// SQL: SELECT id, name FROM users LIMIT 10
💡 性能提升:减少网络传输 + 内存占用,API 响应更快!
🔒 7. 行级锁:高并发下的“占座”神器
// FOR UPDATE:锁定行,防止别人修改
db.Clauses(clause.Locking{Strength: "UPDATE"}).Find(&users)
// FOR SHARE:只读锁,允许多个事务同时读
db.Clauses(clause.Locking{Strength: "SHARE"}).Find(&users)
// NOWAIT:不等待,直接报错(避免死锁)
db.Clauses(clause.Locking{Strength: "UPDATE", Options: "NOWAIT"}).Find(&users)
🎮 适用场景:库存扣减、订单状态变更、抢购系统。
🧮 8. 子查询 & From 子查询:复杂查询不再手写 SQL
// WHERE 子查询
db.Where("amount > (?)", db.Table("orders").Select("AVG(amount)")).Find(&orders)
// FROM 子查询
db.Table("(?) as u", db.Model(&User{}).Select("name", "age")).
Where("age = ?", 18).
Find(&results)
✅ 优势:类型安全 + 自动防注入,告别拼接字符串!
🔄 9. FirstOrInit vs FirstOrCreate:初始化 or 创建?
| 方法 | 行为 |
|---|---|
FirstOrInit | 查不到就初始化 struct(不保存到 DB) |
FirstOrCreate | 查不到就真的插入数据库 |
配合 Attrs 和 Assign 更灵活:
// 找不到时用 Attrs 初始化(仅用于 new)
db.Where(User{Name: "new"}).Attrs(User{Age: 20}).FirstOrInit(&user)
// 无论是否找到,都用 Assign 设置字段(会更新 DB)
db.Where(User{Name: "jinzhu"}).Assign(User{Age: 25}).FirstOrCreate(&user)
🧠 记忆口诀:Attrs 是“备胎”,Assign 是“强制覆盖”。
📦 10. 批量处理:FindInBatches 处理百万数据不 OOM
var results []User
db.Where("processed = ?", false).FindInBatches(&results, 100, func(tx *gorm.DB, batch int) error {
for _, user := range results {
// 处理单个用户
}
tx.Save(&results) // 批量保存
return nil
})
✅ 优势:内存恒定,适合数据迁移、报表生成、定时任务。
🧪 11. 返回更新后的数据
PostgreSQL / Oracle / SQL Server 支持 RETURNING,GORM 也能用:
var users []User
db.Model(&users).
Clauses(clause.Returning{Columns: []clause.Column{{Name: "name"}, {Name: "salary"}}}).
Where("role = ?", "admin").
Update("salary", gorm.Expr("salary * 2"))
// users 现在包含更新后的 name 和 salary!
💡 适用场景:审计日志、消息通知、实时反馈。
🎨 其他实用技巧
- Pluck:只取一列 →
db.Pluck("name", &names) - Scopes:封装常用查询条件 →
db.Scopes(PaidWithCreditCard).Find(&orders) - Optimizer/Index Hints:强制走索引 →
db.Clauses(hints.UseIndex("idx_user_name")) - SQL 表达式更新:
db.Update("price", gorm.Expr("price * 1.1"))
🎉 结语
GORM 不只是“ORM”,它是一个数据库操作瑞士军刀。
掌握这些高级技巧,不仅能写出更健壮的代码,还能在面试时微微一笑:“这个需求,我三行 GORM 就搞定。”
记住:工具再强,也要用在刀刃上。
别为了炫技把简单逻辑写成“魔法咒语” 😅
