Gin + GORM 中 Create 静默失败因 GORM 不校验字段有效性且不报错,需检查 result.Error 和 RowsAffected;ShouldBindJSON 需配合 validator 校验;ID 不应由前端传入;CreatedAt/UpdatedAt 要用指针或 gorm.Model 并禁用 JSON 写入;URL 参数 ID 需用 strconv.ParseUint 安全解析;GET/DELETE 要处理软删除与缓存问题。

为什么 Gin + GORM 组合下 Create 会静默失败?
因为 GORM 的 Create 方法不校验字段有效性,也不抛出错误——哪怕 email 重复、age 超出 uint8 范围,它也可能返回 nil 错误但实际没写入。
- 必须手动检查
result.Error,不能只看err != nil;result.RowsAffected == 0也可能是主键冲突或唯一索引失败 - Gin 的
c.ShouldBindJSON默认不校验结构体 tag(如validate:"required,email"),得配go-playground/validator并显式调用Validate.Struct - 别在
POST /users中直接传入user.ID:GORM 会把它当已存在记录处理,导致INSERT变成UPDATE或报错
如何让 GORM 自动填充 CreatedAt/UpdatedAt 且不被 JSON 覆盖?
靠结构体 tag 控制字段行为,不是靠数据库默认值——GORM 的 CreatedAt 和 UpdatedAt 字段必须声明为指针或使用 gorm.Model,否则更新时会被零值覆盖。
- 定义字段为
*time.Time或用gorm.Model嵌入:type User struct { gorm.Model Name string `json:"name"` Email string `json:"email" gorm:"uniqueIndex"` } - 禁用 JSON 解析时对时间字段的写入:
CreatedAt time.Time `json:"-" gorm:"autoCreateTime"` - 如果用了
sql.NullTime,记得在Scan后判空,否则前端可能收到null却以为是有效时间
Gin 路由中怎么安全地提取并校验 URL 参数中的 id?
别直接用 c.Param("id") 转 uint——字符串解析失败会 panic,且没做范围/合法性检查。
- 统一用
strconv.ParseUint(c.Param("id"), 10, 64),捕获strconv.ErrSyntax并返回400 Bad Request - 查库前先判断 ID 是否为 0(GORM 对 0 ID 默认跳过 WHERE,可能全表扫描)
- 别在
GET /users/:id里用First查不到就返回200 {}:应改用First(&user, id)+ 检查result.Error == gorm.ErrRecordNotFound,对应返回404
为什么 DELETE /users/:id 后前端刷新仍看到旧数据?
常见于没设 HTTP 缓存头,或 GORM 用 Delete 时没加 Unscoped() 导致软删除生效,但前端没区分逻辑删除状态。
立即学习“go语言免费学习笔记(深入)”;
- GORM 默认开启软删除(字段名
DeletedAt),Delete实际是 UPDATE,需显式Unscoped().Delete才物理删 - Gin 返回响应前加
c.Header("Cache-Control", "no-cache"),避免浏览器缓存200 OK响应 - 前端调
DELETE后别依赖服务端重定向,应主动清本地缓存或发GET /users刷新列表
最常被忽略的是软删除和硬删除语义混淆——一个 API 接口要么全走软删(带回收站逻辑),要么明确文档标注“物理删除”,混着用会让前后端对“用户是否存在”产生分歧。










