create只插入且忽略零值,save根据主键存在与否执行insert或update并写入所有字段(含零值),新增时应优先用create确保安全。

新增单条记录时,Create 和 Save 的区别必须分清
直接用 Create 是最安全的默认选择;它会忽略零值字段(比如 0、""、nil),只插入结构体中非零且未被 gorm:"default" 或 gorm:"-" 显式控制的字段。而 Save 会把所有字段(包括零值)都写入数据库,容易意外覆盖已有值。
- 如果结构体字段带
gorm:"default:1",Create会跳过该字段,让数据库用默认值;Save则传0过去,可能破坏业务逻辑 - 主键为零值(如
ID=0)时,Create触发 INSERT;Save在主键为零时也 INSERT,但主键非零时会 UPDATE —— 容易误更新 - 想强制插入(哪怕主键已存在),用
Create;想“有则更新、无则插入”,应改用FirstOrCreate或Save配合事务判断
批量插入要避开 CreateInBatches 的隐式事务陷阱
CreateInBatches 看似方便,但它默认不开启事务,出错时部分数据已写入,无法回滚。尤其在 MySQL 中,若某条记录违反唯一约束,后续批次仍会继续执行。
- 显式包裹事务:
tx := db.Begin() err := tx.CreateInBatches(&users, 100).Error if err != nil { tx.Rollback() return err } return tx.Commit().Error - 批次大小别盲目设大:PostgreSQL 对单次 INSERT 的参数数量有限制(通常 65535),设成 1000 比 10000 更稳妥
- SQLite 不支持多值 INSERT 语法,
CreateInBatches会退化为循环单条插入,性能差;此时建议手写原生 SQL 或换用Create循环 + 批量事务
新增失败时,常见错误信息要能快速定位
报错不是只有 ERROR: duplicate key value violates unique constraint 这一种。GORM 封装后,原始错误常被吞掉,需主动解包。
- 检查约束冲突:
errors.Is(err, gorm.ErrDuplicatedKey)(v1.24+)或用strings.Contains(err.Error(), "duplicate key") - 外键失败在 PostgreSQL 中提示
insert or update on table \"xxx\" violates foreign key constraint,MySQL 是Cannot add or update a child row - 字段超长:PostgreSQL 报
value too long for type character varying(20),对应结构体字段长度没配sizetag,比如漏了gorm:"size:20" - 时间字段为
NULL却没设sql.NullTime或pointer类型,会触发unsupported Scan, storing driver.Value type <nil> into type *time.Time</nil>
嵌套结构新增需手动控制关联行为
GORM 不会自动递归插入关联结构体,除非显式启用 FullSaveAssociations。但这个选项有副作用:它对所有嵌套层级生效,可能导致意外插入重复关联数据。
- 只对特定字段启用:
db.Session(&gorm.Session{FullSaveAssociations: true}).Create(&order),其中order包含User和Items []Item - 更可控的做法是分步操作:先
Create主表,再用主表 ID 赋值给子表,最后批量Create子表 - 若子表结构体含主键且值非零,
FullSaveAssociations会尝试 UPDATE 而非 INSERT,导致失败;务必确保子表主键为零值或设gorm:"primaryKey;autoIncrement"
0001-01-01,后者让数据一致性完全失控。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











