gorm的create默认跳过零值字段,需用select显式指定字段;save全量更新含零值,updates传struct时零值被忽略;delete无条件会清空整表;first未找到返回gorm.errrecordnotfound需类型断言处理。

为什么直接用 Create 会丢失零值字段
当你用 Create 插入一个 struct,GORM 默认跳过所有零值字段(比如 0、""、false),哪怕你明确想存 status = 0 或 price = 0.0。这不是 bug,是 GORM 的“零值忽略”策略在起作用。
解决办法是显式指定要插入的字段:
db.Select("name", "status", "price").Create(&user)
或者更稳妥地,在 struct tag 里加 gorm:"default:0" 并配合 omitempty 控制序列化逻辑 —— 但注意:tag 中的 default 只影响数据库建表时的 DEFAULT 约束,不改变 Create 行为。
- 如果字段必须写入(哪怕为零),就用
Select()显式列出 - 避免依赖
omitempty做数据库写入控制,它只对 JSON 有效 -
CreateInBatches同样受零值影响,批量插入也要Select
Update 时 Save 和 Updates 的关键区别
Save 是全量更新:它把整个 struct 当作新值,连同零值一起覆盖;Updates 是部分更新:只改传入 map 或 struct 中非零/非空字段(同样受零值规则限制)。
典型陷阱:
user.Status = 0 db.Save(&user) // ✅ 写入 status = 0
db.Model(&user).Updates(map[string]interface{}{"status": 0}) // ✅ 写入 status = 0
db.Model(&user).Updates(&User{Status: 0}) // ❌ 不生效!struct 中其他字段为零值,被跳过
- 用
Updates传 struct 时,GORM 按字段零值判断是否更新 —— 所以别传完整 struct - 想安全更新单个字段,优先用
Model().Update("column", value) -
Save在主键存在时是 UPDATE,不存在时是 INSERT,容易误触发插入
删除操作必须加条件,否则 Delete 会清空整表
GORM 的 Delete 方法如果没有 WHERE 条件,默认作用于整个模型对应表 —— 这不是防呆设计,是明确行为。线上误写 db.Delete(&User{}) 就等于 DELETE FROM users。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
安全做法只有两种:
- 永远用带主键的实例:
db.Delete(&user)(前提是user.ID已赋值) - 显式加 WHERE:
db.Where("id = ?", id).Delete(&User{})
额外提醒:Unscoped().Delete 会绕过软删除,慎用;软删除字段名默认是 DeletedAt,改名后需同步配置 gorm.Model 或全局 SetupJoinTable。
查询结果为空时,First/Take 报 record not found 怎么处理
这个错误是 gorm.ErrRecordNotFound,不是 panic,但很多人用 if err != nil 直接退出,忽略了“查不到”是合法业务状态。
正确姿势是类型断言判断:
err := db.First(&user, 999).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
// 处理未找到
} else if err != nil {
// 处理其他错误(如连接失败)
}
- 别用
Find查单条,它返回切片且不报错,容易掩盖逻辑问题 -
First找不到时返回 error;Take返回任意一条(可能非预期);Last同理 - 需要判空又不想写 err 判断?用
Limit(1).Find(&users)+ 检查len(users) == 0
关联查询、预加载、事务嵌套这些场景下,零值处理和错误判断会叠加复杂度,建议每个 Create/Update/Delete 调用后都确认是否真按预期执行了 SQL —— 开启 logger.Default.LogMode(logger.Info) 看日志最实在。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










