gorm的save使用中,发现当模型通过save保存时,如果模型没有发生改变,会包主键冲突错误,这只在事务中出现,独立使用save同样的场景不会报错。
错误
使用grom的save初衷是想存在时更新,不存在时自动创建,在模型不变时执行save报下面的错误Error 1062 (23000): Duplicate entry '336ea11bd7254ee7bb406604bfa43bf2' for key 'histories.PRIMARY'
错误code
使用事务并遍历保存模型的原因是,save没有设置批量个数的方式,当一次保存的模型数过大时,会引发错误(具体数和硬件配置等有关),所以为了避免,显示的做了事务循环更新
err := r.db.Transaction(func(tx *gorm.DB) error {
for _, m := range newModels {
if err := tx.Save(m).Error; err != nil {
return err
}
}
return nil
})
错误分析
grom的save
在很多地方都使用,从来没遇到过这个错误,并且save的逻辑是会先判断存在更新,不存在创建,所以出现主键重复的错误很奇怪,debug数据发现只会出现子更新的数据没有任何变化的情况下。确认了重现的场景,但还是不太能理解错误的原因,于是又写了测试代码来验证save
,最终发现,直接使用save
即使模型不变也不会出现问题,只会在事务中出现问题。
解决办法
在更新模型前加了判断,如果没有变化就直接跳过了(业务中本身有对变化字段的处理,只是一开始没处理这个分支)