gorm 有哪些常用特性?软删除、钩子等有哪些坑?

一句话结论:gorm 是 Go 最常用的 ORM:结构体即表模型,支持链式查询、Preload 预加载、Transaction 事务、AutoMigrate、钩子与软删除。常见坑集中在:共用 DB 实例导致查询条件累积、软删除与唯一索引冲突、Updates 用结构体时不更新零值、软删数据默认查不到、钩子里误改字段等。

常用特性速览

特性说明
模型结构体标签 gorm:"column:name;index;unique" 映射表
预加载Preload("Orders") / Joins 减少 N+1 查询
事务db.Transaction(func(tx) error {...}),返回 error 自动回滚
软删除字段 gorm.DeletedAt:删除变 UPDATE,查询自动带 deleted_at IS NULL
钩子BeforeSave/BeforeCreate/AfterCreate/BeforeUpdate/AfterFind 等
迁移AutoMigrate 建表与加列(不做删列等复杂变更)
链式查询Where/Order/Limit 通常只在当次生效(复用 DB 除外)

高频坑与对策

  • 软删除加唯一索引:删除后同 key 再插入会撞唯一索引——把 deleted_at 一起放进唯一索引(组合唯一)。
  • 查不到“已删”数据:默认查询排除软删行,要查用 Unscoped(),彻底删除也是 Unscoped().Delete。
  • Updates 结构体跳过零值:想置 0/空要用 map 或 Select 指定列。
  • 复用 db 实例条件累积:一次 Where 后再次使用同一 db 会带着旧条件,用 db.Session(&gorm.Session{}) 取全新会话。
  • First 查不到返回 ErrRecordNotFound,要显式处理而不是一路忽略。
  • 大批量插入逐条执行很慢:用 CreateInBatches 分批插入。
  • 生产环境记得开慢 SQL 日志/Logger,方便定位 N+1 与慢查询。
type User struct {
	ID        uint           `gorm:"primarykey"`
	Name      string         `gorm:"uniqueIndex:uk_name_del"`
	DeletedAt gorm.DeletedAt `gorm:"uniqueIndex:uk_name_del"` // 软删后允许重名
}

func biz(db *gorm.DB) error {
	return db.Transaction(func(tx *gorm.DB) error {
		if err := tx.Create(&User{Name: "alice"}).Error; err != nil {
			return err // 任一步失败整体回滚
		}
		return tx.Model(&User{}).Where("id = ?", 1).
			Update("name", "bob").Error
	})
}

常见追问 / 记忆点

  • 追问:软删除是怎么实现的?——Delete 被钩子改写成 UPDATE deleted_at=now,查询层自动追加过滤条件。
  • 追问:钩子里想改本次操作的数据怎么办?——在 BeforeXxx 中直接改传入的结构体字段即可生效。
  • 记忆点:链式复用要 Session;软删记住唯一索引坑;Updates 零值不生效;生产开慢日志。
笔记加载中…