GORM 并发执行 Save 更新记录报:Error 1062 (23000)

本文讲述了在使用GORMv1.24.6时,并发调用Save方法更新同一记录可能导致的Duplicateentry错误,原因是版本更新优化可能导致误判新记录插入,建议避开这个版本或使用后续版本以避免问题。

在这里插入图片描述

0.前言

大咖好呀,我是恋喵大鲤鱼。

GORM(Golang Object Relational Mapping)是一个用于 Golang 的对象关系映射(ORM)库。

当需要插入或更新记录时,一般使用 Save 方法。如果只是插入,也可以使用 Create 方法。在使用 Save 方法多次更新同一条记录到 MySQL 时,却遇到了一个奇怪的问题。

1.Save 简介

先看一下 Save 方法的描述:

// Save updates value in database. If value doesn't contain a matching primary key, value is inserted.
func (db *DB) Save(value interface{}) (tx *DB)

Save 有两个作用,创建或更新记录。如果待保存的值不包含主键,则执行 Create,否则执行 Update(包含所有字段)。

如果是执行 Update 的话,模型字段即使是零值也会更新。这一点与 Updates 方法不同,Updates 默认只会更新非零值。

2.问题

在使用 GORM v1.24.6 时,在并发调用 Save 方法更新同一个记录会报如下错误:

Error 1062 (23000): Duplicate entry 'xxx' for key 'PRIMARY'

奇怪的是,串行调用则不会报错。

无独有偶,我发现在 GORM Github 仓库已经有人提了类似的 Issues。

Duplicate primary key error returned when saving unmodified object #6171

我在该 Issue 中也补充了我遇到的问题。

在这里插入图片描述
另外,我还测试了一下上一个版本 v1.24.5 没有这个问题,说明该 Bug 是版本 v1.24.6 引入的新 Bug,非历史遗留的 Bug。

3.原因

GORM 社区非常活跃,在我补充问题的当天便有人进行了回复。

在这里插入图片描述

从回复中可以看到,在 Issue #6171 之前,已经有人提了 PR #6149 来解决这个问题,只是还未被合入。

顺着回复的内容,找到 commit f387433,看了下提交内容。

在这里插入图片描述

从 commit message “Fix Save with stress tests” 和变更内容,推测 jinzhu 大佬是为了优化 Save 的更新性能,将插入前判断记录是否存在的条件去掉了。多次调用 Save 更新同一条记录时,发现记录没有被更新,则认为是新记录,便进行插入,然后就出现了主键冲突的错误。

在 Mar 23 当天,jinzhu 大佬可能已经意识到了问题的存在,便将 PR #6149 合入到主干,修复了这个问题。

4.小结

如果大家遇到了同样的问题,请跳过 v1.24.6,使用之前或之后的版本,比如前一个版本 v1.24.5 或后一个版本 v1.25.0。

如果您喜欢这篇文章,欢迎关注微信公众号“恋喵大鲤鱼”了解最新精彩内容。


参考文献

GORM
Duplicate primary key error returned when saving unmodified object #6171

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值