GORM 高级技巧:让你的数据库操作又快又稳!

🔐 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查不到就真的插入数据库

配合 AttrsAssign 更灵活:

// 找不到时用 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 就搞定。”

记住:工具再强,也要用在刀刃上。
别为了炫技把简单逻辑写成“魔法咒语” 😅


0
0
0
0
评论
未登录
暂无评论