create不报错但数据库没写入,因gorm只检查sql执行错误而不校验字段合法性(如uint8溢出、主键冲突),须显式检查result.error和rowsaffected;关键字段需validator校验,id非零会触发update语义错乱,时间字段须用* time.time或gorm.model并禁json覆盖。

Create不报错但数据库没写入?
这是 Gin + GORM 最典型的静默失败场景。GORM 的 Create 方法只检查 SQL 执行是否出错,不校验字段值合法性(比如 uint8 字段传了 300、主键冲突、违反唯一索引等),导致 err == nil 但 result.RowsAffected == 0。
- 必须显式检查
result.Error和result.RowsAffected,不能只判err != nil - 对关键字段做业务校验:用
go-playground/validator配合Validate.Struct(),比如Email string `binding:"required,email"` - 避免结构体带非零
ID调用Create——GORM 会自动转成UPDATE,语义错乱 - 插入后立刻查不到?确认是否启用了软删除(
DeletedAt *time.Time),默认查询会自动过滤已软删记录
CreatedAt/UpdatedAt 自动填充却被 JSON 覆盖?
时间字段被前端传的空值或非法字符串覆盖,本质是 JSON 解析和 GORM tag 冲突。GORM 不信任数据库的 DEFAULT CURRENT_TIMESTAMP,必须靠结构体 tag 控制行为。
- 字段类型必须是
*time.Time或嵌入gorm.Model(含CreatedAt/UpdatedAt) - 禁用 JSON 写入:
CreatedAt time.Time `json:"-" gorm:"autoCreateTime"` - 若用
sql.NullTime,Scan后必须判断.Valid,否则前端收到null无法区分“未设置”和“空时间” - 禁止同时写
json:"created_at"和gorm:"column:created_at",容易覆盖冲突
Delete 后刷新页面还显示数据?
不是没删,是软删除生效了,且响应没禁缓存。GORM 默认开启软删除(只要结构体含 DeletedAt *time.Time),Delete 实际执行的是 UPDATE SET deleted_at = NOW()。
- 前端需主动过滤:API 响应里加
DeletedAt字段,前端逻辑判断是否隐藏 - 响应头加
c.Header("Cache-Control", "no-cache, no-store, must-revalidate"),防止浏览器/CDN 缓存旧数据 - 硬删要显式调用
Unscoped().Delete(),但慎用——会绕过所有 GORM 钩子和关联逻辑 - 注意:软删除后
First、Find默认不返回已删记录;如需查,必须Unscoped()
AutoMigrate 为什么没建表或字段没更新?
AutoMigrate 只增不减、只改不删,且不会同步已有数据。它只根据当前 Go 结构体生成缺失的表或新增字段,但不会修改字段类型、删除废弃字段,也不会补全历史数据。
- 字段类型变更(如
string→*string)不会触发 ALTER COLUMN,需手动 SQL 或工具处理 - 新增字段默认值为空,不会给已有行填充;要用
gorm:"default:0"或迁移后跑 SQL UPDATE - 表名不一致?重写
TableName()方法,别依赖默认蛇形转换 - 首次运行一定要确保
DB.AutoMigrate(&Model{})成功执行,建议在initDB里 panic 错误
最常被忽略的是:GORM 的“默认行为”几乎全是为兼容性妥协的设计,不是为你当前业务服务的。每个 Create、Update、Delete 背后都有隐式条件,不显式控制就等于把逻辑交给运气。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











