基于GORM如何实现CreateOrUpdate


这篇文章主要讲解了“基于GORM如何实现CreateOrUpdate”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“基于GORM如何实现CreateOrUpdate”吧!我们先来看下 GORM 提供了那些方法来支持我们往数据库插入数据,对 GORM 比较熟悉的同学可以忽略这部分:插入一条记录到数据库,注意需要通过数据的指针来创建,回填主键;赋值 Dest 后直接进入 Create 的 callback 流程。保存所有的字段,即使字段是零值。如果我们传入的结构主键为零值,则会插入记录。关注点:在 reflect.Struct 的分支,判断 PrimaryFields 也就是主键列是否为零值,如果是,直接开始调用 Create 的 callback,这也和 Save 的说明匹配;switch 里面用到了 fallthrough 关键字,说明 switch 命中后继续往下命中 default;如果我们没有用 Select() 方法指定需要更新的字段,则默认是全部更新,包含所有零值字段,这里用的通配符 *如果主键不为零值,说明记录已经存在,这个时候就会去更新。事实上有一些业务场景下,我们可以用 Save 来实现 CreateOrUpdate 的语义:首次调用时主键ID为空,这时 Save 会走到 Create 分支去插入数据。随后调用时存在主键ID,触发更新逻辑。但 Save 本身语义其实比较混乱,不太建议使用,把这部分留给业务自己实现,用Updates,Create用起来更明确些。Update 前者更新单个列。Updates 更新多列,且当使用 struct 更新时,默认情况下,GORM 只会更新非零值的字段(可以用 Select 指定来解这个问题)。使用 map 更新时则会全部更新。这里也能从实现中看出来一些端倪。Update 接口内部是封装了一个 map[string]interface{},而 Updates 则是可以接受 map 也可以走 struct,最终写入 Dest。获取第一条匹配的记录,或者根据给定的条件初始化一个实例(仅支持 struct 和 map)注意,Init 和 Create 的区别,如果没有找到,这里会把实例给初始化,不会存入 DB,可以看到 RowsAffected == 0 分支的处理,这里并不会走 Create 的 callback 函数。这里的定位是一个纯粹的读接口。获取第一条匹配的记录,或者根据给定的条件创建一条新纪录(仅支持 struct 和 map 条件)。FirstOrCreate可能会执行两条sql,他们是一个事务中的。注意区别,同样是构造 queryTx 去调用 Find 方法查询,后续的处理很关键:若没有查到结果,将 where 条件,Attrs() 以及 Assign() 方法赋值的属性写入对象,从源码可以看到是通过三次 assignInterfacesToValue 实现的。属性更新后,调用 Create 方法往数据库中插入;若查到了结果,但 Assign() 此前已经写入了一些属性,就将其写入对象,进行 Updates 调用。第一个分支好理解,需要插入新数据。重点在于 else if len(db.Statement.assigns) > 0 分支。我们调用 FirstOrCreate 时,需要传入一个对象,再传入一批条件,这批条件会作为 Where 语句的部分在一开始进行查询。而这个函数同时可以配合 Assign() 使用,这一点就赋予了生命力。不管是否找到记录,Assign都会将属性赋值给 struct,并将结果写回数据库。这种方式充分利用了 Assign 的能力。我们在上面 FirstOrCreate 的分析中可以看出,这里是会将 Assign 进来的属性应用到 struct 上,写入数据库的。区别只在于是插入(Insert)还是更新(Update)。所以,要实现 CreateOrUpdate,我们可以将需要 Update 的属性通过 Assign 函数放进来,随后如果通过 Where 找到了记录,也会将 Assign 属性应用上,随后 Update。这样的思路一定是可以跑通的,但使用之前要看场景。为什么?因为参看上面源码我们就知道,FirstOrCreate 本质是 Select + Insert 或者 Select + Update。无论怎样,都是两条 SQL,可能有并发安全问题。如果你的业务场景不存在并发,可以放心用 FirstOrCreate + Assign,功能更多,适配更多场景。而如果可能有并发安全的坑,我们就要考虑方案二:Upsert。鉴于 MySQL 提供了 ON DUPLICATE KEY UPDATE 的能力,我们可以充分利用唯一键的约束,来搞定并发场景下的 CreateOrUpdate。这里依赖了 GORM 的 Clauses 方法,我们来看一下:这里添加进来一个 Clause 之后,会调用 MergeClause 将语句进行合并,而 OnConflict 的适配是这样:初阶的用法中,我们只需要关注三个属性:DoNothing:冲突后不处理,参照上面的 Build 实现可以看到,这里只会加入 DO NOTHING;DoUpdates: 配置一批需要赋值的 KV,如果没有指定 DoNothing,会根据这一批 Assignment 来写入要更新的列和值;UpdateAll: 冲突后更新所有的值(非 default tag字段)。需要注意的是,所谓 OnConflic免费云主机域名t,并不一定是主键冲突,唯一键也包含在内。所以,使用 OnConflict 这套 Upsert 的先决条件是【唯一索引】或【主键】都可以。生成一条SQL语句,并发安全。如果没有唯一索引的限制,我们就无法复用这个能力,需要考虑别的解法。感谢各位的阅读,以上就是“基于GORM如何实现CreateOrUpdate”的内容了,经过本文的学习后,相信大家对基于GORM如何实现CreateOrUpdate这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是百云主机,小编将为大家推送更多相关知识点的文章,欢迎关注!

相关推荐: vue怎么实现选项卡点击切换且能滑动切换功能

本文小编为大家详细介绍“vue怎么实现选项卡点击切换且能滑动切换功能”,内容详细,步骤清晰,细节处理妥当,希望这篇“vue怎免费云主机域名么实现选项卡点击切换且能滑动切换功能”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。具体代码如下…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 02/16 16:29
下一篇 02/16 16:30

相关推荐