GORM新增数据核心是Create方法,必须传结构体指针(如&user)以支持主键回填和字段映射;需配合RowsAffected与Error双重校验插入结果,批量场景应优先使用CreateInBatches而非循环Create。

调用 Create 方法是最直接的方式
GORM 新增数据的核心就是 Create 方法,它会自动生成 INSERT 语句并执行。传入一个已赋值的结构体指针即可,GORM 会自动映射字段到对应表列。
常见错误是传入值类型(如 user)而非指针(如 &user),导致 GORM 无法修改结构体内部字段(比如主键回填),也容易触发“record not found”类误报。
- 必须传指针:
db.Create(&user),不是db.Create(user) - 结构体字段需有可导出名(首字母大写)且带
gormtag(如gorm:"primaryKey")才能被识别 - 若数据库设了默认值(如
created_at),GORM 不会主动设置,除非你显式启用AutoCreateTime或手动赋值
Create 返回结果里藏着关键状态
别只看 err 是否为 nil ——Create 返回的 *gorm.DB 实例自带 RowsAffected 和 Error,它们比裸 err 更准。
典型陷阱:插入唯一索引冲突时,err 可能是 nil(尤其在 SQLite 或某些 MySQL 配置下),但 result.RowsAffected == 0;反之,PostgreSQL 通常会返回 unique_violation 错误。
- 检查影响行数:
if result.RowsAffected == 0 { /* 插入失败或被忽略 */ } - 统一捕获冲突:
errors.Is(err, gorm.ErrDuplicatedKey)(GORM v1.25+) - 避免用
result.Error == nil判定成功,应优先结合RowsAffected
批量插入用 CreateInBatches,别硬套 Create
一次性插几百条还用 Create 循环?性能会断崖下跌。每条都走一次事务、一次 prepare、一次 round-trip,延迟和连接压力陡增。
CreateInBatches 是 GORM 内置的批量方案,底层生成单条 INSERT ... VALUES (...), (...), (...) 语句,效率提升明显,但也带来几个约束:
- 切片长度不能超过数据库限制(MySQL 默认 max_allowed_packet 约 4MB,换算下来约几千条)
- 所有记录必须属于同一结构体类型,且字段顺序/空值逻辑一致
- 不支持混合主键策略(比如部分记录带 ID、部分不带),否则可能覆盖或冲突
- 示例:
db.CreateInBatches(users, 100)表示每批 100 条
新增前没校验 BeforeCreate 钩子就动手?风险很高
很多人直接 Create 就完事,但业务逻辑常要求插入前做转换或拦截——比如哈希密码、补全 UUID、拒绝非法邮箱。靠外层 if 判断既重复又易漏。
GORM 的 BeforeCreate 钩子是天然入口,但它有个关键细节:钩子函数接收的是指针,但修改后必须显式返回 error 才能中断流程;返回 nil 才继续插入。
- 钩子定义要放在模型结构体上,方法签名必须是:
func (u *User) BeforeCreate(tx *gorm.DB) error - 如果想跳过插入,返回非
nilerror(如errors.New("invalid email")),此时Create会立即返回该 error - 钩子里改字段(如
u.Password = hash(u.Password))无需额外操作,GORM 自动取值 - 注意:钩子在事务内执行,若中途 panic,整个事务回滚
GORM 的新增看着简单,但主键生成策略、钩子执行时机、错误分类粒度、批量边界控制,这些地方一旦忽略,上线后就容易出现静默失败或性能抖动。


















