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

在这里插入图片描述

文章目录

  • 0.前言
  • 1.Save 简介
  • 2.问题
  • 3.原因
  • 4.小结
  • 参考文献

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


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部