用 gin 快速搭建 user crud 路由骨架,嵌入 gorm.model 确保主键识别与正确 sql 生成,区分 save(全量)与 updates(部分)更新,避免 automigrate 上线使用,显式配置连接池并补充字段校验。

用 gin 快速搭起 User CRUD 路由骨架,别碰 net/http 手写 mux
直接上 gin —— 它默认带 JSON 解析、路径参数提取、中间件链,比原生 net/http 少写 80% 胶水代码。手写 http.ServeMux 配路由 + json.Unmarshal 拆包 + 状态码手动设,容易漏 Content-Type 或返回空体却没设 204。
实操建议:
-
gin.Default()自带日志和 recovery 中间件,开发期够用;上线前换成gin.New()+ 显式挂载,避免 recovery 吞掉 panic 细节 - User 列表接口用
GET /users,单个查用GET /users/:id,:id会被c.Param("id")提取,别写成/users?id=123—— 那是查询参数,不是路径参数 - 创建 User 的
POST /users必须校验c.ShouldBindJSON(&user)返回值,否则前端传错字段类型(比如"age": "abc"),后端静默接受空结构体
gorm.Model 和裸 struct 的选择:为什么 User 结构体要嵌入 gorm.Model
嵌入 gorm.Model 不只是为了自动带 ID、CreatedAt 这些字段,关键是它让 gorm 能识别主键、生成正确 SQL。不用它,你得手动在 struct tag 里写 gorm:"primaryKey",还容易漏 gorm:"column:id" 导致字段映射错乱。
常见错误现象:
立即学习“go语言免费学习笔记(深入)”;
- 删用户时调
db.Delete(&user)却删不掉 —— 因为没主键,gorm默认按全字段匹配,而内存里的user可能只填了ID,其余字段是零值,SQL 变成WHERE name = '' AND email = '' - 用
db.First(&user, 123)查不到数据,但换db.First(&user, "id = ?", 123)又可以 —— 原因就是没嵌gorm.Model,gorm不知道哪个字段是主键
示例片段:
type User struct {
gorm.Model // ← 这行不能少
Name string `gorm:"not null"`
Email string `gorm:"uniqueIndex"`
}
更新操作用 Save 还是 Updates?字段零值怎么处理
Save 是全量更新(会把 struct 里所有字段写进 SQL,包括零值),Updates 是部分更新(只写非零、非 nil 字段)。User 编辑页如果只改邮箱,用 Save 会把 Name 设成空字符串,除非你提前从 DB 查一遍再合并。
使用场景:
- 前端 PATCH /users/123 只传
{"email": "new@x.com"}→ 用db.Model(&user).Updates(updateMap),updateMap是map[string]interface{} - 需要严格审计字段变更(比如只允许改邮箱,禁止改姓名)→ 先查出旧记录,对比字段差异,再构造
Updates参数 - 注意
int类型零值是0,不是 “未设置”,所以Updates对Age int字段不会跳过0—— 解决办法是用指针*int,或显式传map[string]interface{}{"age": 0}
数据库初始化和迁移:别在 main() 里硬编码 AutoMigrate
AutoMigrate 是开发期省事,但上线后它会锁表、可能失败(比如加非空字段没给默认值),而且无法回滚。真实项目里,应该用 migrate 工具(如 golang-migrate/migrate)管理 SQL 文件。
实操建议:
- 开发环境可保留
db.AutoMigrate(&User{}),但加个开关:if os.Getenv("ENV") == "dev" { ... } - 字段变更必须写 migration 文件,例如
20240501_add_user_status.up.sql,内容是ALTER TABLE users ADD COLUMN status VARCHAR(20) DEFAULT 'active'; - 连接池配置别用默认值:
&sql.DB的SetMaxOpenConns(10)和SetMaxIdleConns(5)得显式设,否则高并发下可能耗尽数据库连接
最常被忽略的点:Gin 的 c.ShouldBindJSON 默认不校验字段是否为空,gorm 的 not null tag 只在建表时生效,运行时不会拦截空字符串插入。得靠 validator 库或手写校验逻辑,否则数据库报错才暴露问题。










