保存所有字段

  Save 会保存所有的字段,即使字段是零值、

db.First(&user, 5)
user.Name = sql.NullString{"王八", true}
user.Age = 9
db.Debug().Save(&user)
// UPDATE `users` SET `name`='王八',`age`=9,`uuid`='c3987500-bf01-412b-aaab-685285e04037',`created_at`='2021-11-17 13:34:30' WHERE `id` = 5

  

更新单个列

  当使用 Update 更新单个列时,你需要指定条件,否则会返回 ErrMissingWhereClause 错误,查看 Block Global Updates 获取详情。当使用了 Model 方法,且该对象主键有值,该值会被用于构建条件,例如:

db.Debug().Model(&User{}).Where("age = ?", 12).Update("name", "张无忌")
// UPDATE `users` SET `name`='张无忌' WHERE age = 12

var user User
db.First(&user, "age = ?", 9)
db.Debug().Model(&user).Update("name", "龟")
// UPDATE `users` SET `name`='龟' WHERE `id` = 5 // 由于user对象主键有值,所以就会被用于构建条件

  

更新多列

  Updates 方法支持 struct 和 map[string]interface{} 参数。当使用 struct 更新时,默认情况下,GORM 只会更新非零值的字段

// 根据struct更新属性,只会更新非零值字段
var user User
db.First(&user, 7)
db.Debug().Model(&user).Updates(User{Name: sql.NullString{"哈哈2", true}, Age: 0})
// UPDATE `users` SET `name`='哈哈2' WHERE `id` = 7 // 结构体只会更新非零值字段
// 根据map更新属性,零值和非零值字段都会更新
var user User
db.Debug().First(&user, 7).Updates(map[string]interface{}{
"name": "", "age": 18,
})
// SELECT * FROM `users` WHERE `users`.`id` = 7 ORDER BY `users`.`id` LIMIT 1
// UPDATE `users` SET `age`=18,`name`='' WHERE `users`.`id` = 7 AND `id` = 7 ORDER BY `users`.`id` LIMIT 1

  注意 当通过 struct 更新时,GORM 只会更新非零字段。 如果您想确保指定字段被更新,你应该使用 Select 更新选定字段,或使用 map 来完成更新操作

更新选定字段

  如果您想要在更新时选定、忽略某些字段,您可以使用 SelectOmit

// select+map更新
db.Debug().Model(new(User)).Where("id = ?", 7).Select("name").Updates(map[string]interface{}{
"uuid": "def214f8-4b39-11ec-a337-fc3fdbb57b40",
"created_at": time.Now(),
"name": "哈哈哈",
})
// UPDATE `users` SET `name`='哈哈哈' WHERE id = 7

// Omit + map更新
db.Debug().Model(new(User)).Where("id = ?", 7).Omit("name").Updates(map[string]interface{}{
"uuid": "def214f8-4b39-11ec-a337-fc3fdbb57b40",
"created_at": time.Now(),
"name": "哈哈哈",
})
// UPDATE `users` SET `created_at`='2021-11-22 10:31:52.602',`uuid`='def214f8-4b39-11ec-a337-fc3fdbb57b40' WHERE id = 7

// select + struct更新, 会更新零值的字段
db.Debug().Model(&User{}).Where(map[string]interface{}{"id": 7}).Select("name", "age").Updates(User{
Name: sql.NullString{"struct2", true},
Age: 0,
})
// UPDATE `users` SET `name`='struct2',`age`=0 WHERE `id` = 7

// Omit + struct更新, 不会更新零值的字段
db.Debug().Model(&User{}).Where(map[string]interface{}{"id": 7}).Omit("name").Updates(User{
Name: sql.NullString{"struct2", true},
Age: 0,
})
// 此语句不执行

// select 所有字段,(更新包括零值字段的所有字段)
db.Debug().Model(new(User)).Where("id = ?", 7).Select("*").Updates(User{
Name: sql.NullString{"", true},
Age: 34,
CreatedAt: time.Now(),
})
// UPDATE `users` SET `id`=0,`name`='',`age`=34,`uuid`='00000000-0000-0000-0000-000000000000',`created_at`='2021-11-22 10:45:21.161' WHERE id = 7

// Omit 更新除name字段的所有字段,(包括零值字段的所有字段)
db.Debug().Model(new(User)).Where("id = ?", 0).Omit("name").Updates(User{
Name: sql.NullString{"", true},
Age: 44,
CreatedAt: time.Now(),
ID: 7,
})
// UPDATE `users` SET `id`=7,`age`=44,`created_at`='2021-11-22 10:51:23.298' WHERE id = 0

  

更新 Hook

  对于更新操作,GORM 支持 BeforeSaveBeforeUpdateAfterSaveAfterUpdate 钩子,这些方法将在更新记录时被调用

func (u *User) BeforeUpdate(*gorm.DB) (err error) {
fmt.Println("User BeforeUpdate执行了")
return
}
func (u *User) AfterUpdate(*gorm.DB) (err error) {
fmt.Println("User AfterUpdate执行了")
return
}
func (u *User) BeforeSave(*gorm.DB) (err error) {
fmt.Println("User BeforeSave执行了")
return
}
func (u *User) AfterSave(*gorm.DB) (err error) {
fmt.Println("User AfterSave执行了")
return
}

// 更新Hook BeforeSave、AfterSave、BeforeUpdate、AfterUpdate
// 钩子方法的函数签名是:func(*gorm.DB) error
spew.Println("更新前")
db.Debug().Model(new(User)).Where("id = ?", 7).Updates(User{
Name: sql.NullString{"hello", true},
Age: 36,
})
spew.Println("更新后")

/* 打印结果
  更新前
  User BeforeSave执行了
  User BeforeUpdate执行了
  User AfterSave执行了
  User AfterUpdate执行了
  2021/11/22 11:26:26 C:/Users/mayanan/Desktop/pro_go/topgoer_gorm/main.go:114 SLOW SQL >= 200ms
  [260.657ms] [rows:1] UPDATE `users` SET `name`='hello',`age`=36 WHERE id = 7
  更新后
*/

  

批量更新

  如果您尚未通过 Model 指定记录的主键,则 GORM 会执行批量更新

// 根据struct批量更新
db.Debug().Model(new(User)).Where("name <> ?", "").Updates(User{
Name: sql.NullString{"mayanan", true},
Age: 28,
})
// UPDATE `users` SET `name`='mayanan',`age`=28 WHERE name <> ''

// 根据map批量更新
db.Debug().Model(new(User)).Where("name <> ?", "").Updates(map[string]interface{}{
"name": "王五", "age": 39,
})
// UPDATE `users` SET `age`=39,`name`='王五' WHERE name <> ''

  

阻止全局更新

如果在没有任何条件的情况下执行批量更新,默认情况下,GORM 不会执行该操作,并返回 ErrMissingWhereClause 错误

对此,你必须加一些条件,或者使用原生 SQL,或者启用 AllowGlobalUpdate 模式,例如:

// gorm 默认阻止全局更新
db.Debug().Model(&User{}).Updates(map[string]interface{}{
"name": "lisi", "age": 33,
})
// 报错:WHERE conditions required

db.Debug().Model(&User{}).Where("1 = 1").Updates(map[string]interface{}{
"name": "lisi", "age": 33,
})
// UPDATE `users` SET `age`=33,`name`='lisi' WHERE 1 = 1

db.Debug().Exec("update users set name = ?", "田七")
// update users set name = '田七';

db.Debug().Session(&gorm.Session{AllowGlobalUpdate: true}).Updates(User{
Age: 35,
})
// UPDATE `users` SET `age`=33

更新的记录数

  获取受更新影响的行数

// 获取受更新影响的行数
ret := db.Debug().Session(&gorm.Session{AllowGlobalUpdate: true}).Updates(User{
Age: 37,
})
spew.Dump(ret.RowsAffected) // 5 更新的记录数
spew.Dump(ret.Error) // nil 更新产生的错误

  

高级选项

使用 SQL 表达式更新

  GORM 允许使用 SQL 表达式更新列,例如:

var user User
db.First(&user)
db.Debug().Model(&user).Update("age", gorm.Expr("age * ? + ?", 2, 3))
// UPDATE `users` SET `age`=age * 2 + 3 WHERE `id` = 1

// map里面使用sql表达式
var user []User
db.Find(&user)
db.Debug().Model(&user).Updates(map[string]interface{}{
"age": gorm.Expr("(age - ?) / ?", 2, 2),
})
// UPDATE `users` SET `age`=(age - 2) / 2 WHERE (`id` = 1 OR `id` = 2 OR `id` = 5 OR `id` = 6 OR `id` = 7)

// UpdateColumn里面使用sql表达式
var user []User
db.Find(&user)
db.Debug().Model(&user).UpdateColumn("age", gorm.Expr("age / ? - ?", 2, 2))
// UPDATE `users` SET `age`=age / 2 - 2 WHERE (`id` = 1 OR `id` = 2 OR `id` = 5 OR `id` = 6 OR `id` = 7)

根据子查询进行更新

  使用子查询更新表

// 根据子查询更新表
var user User
db.First(&user, 6)
subQuery := db.Model(new(Email)).Select("user_id").Where("email = ?", "abc@qq.com")
db.Debug().Model(&user).Update("age", subQuery)
// UPDATE `users` SET `age`=(SELECT `user_id` FROM `emails` WHERE email = 'abc@qq.com') WHERE `id` = 6

subQuery := db.Table("emails as e").Select("email").Where("user_id = ?", 10)
db.Debug().Table("users as u").Where("id = ?", 7).Update("name", subQuery)
// UPDATE users as u SET `name`=(SELECT email FROM emails as e WHERE e.user_id = 11) WHERE id = 5

subQuery := db.Table("emails as e").Select("email").Where("user_id = ?", 2)
db.Debug().Table("users as u").Where("id = ?", 2).Updates(map[string]interface{}{
"name": subQuery,
})
// UPDATE users as u SET `name`=(SELECT email FROM emails as e WHERE user_id = 2) WHERE id = 2

  

不使用 Hook 和时间追踪

如果您想在更新时跳过 Hook 方法且不追踪更新时间,可以使用 UpdateColumnUpdateColumns,其用法类似于 UpdateUpdates

// 更新单个列
db.Debug().Table("users").Where("id = ?", 1).UpdateColumn("name", "李四")
// UPDATE `users` SET `name`='李四' WHERE id = 1

// 更新多个列
db.Debug().Table("users").Where("id = ?", 2).UpdateColumns(map[string]interface{}{
"name": "王五", "age": 31,
})
// UPDATE `users` SET `age`=31,`name`='王五' WHERE id = 2

db.Debug().Table("users").Where("id = ?", 2).Select("name").UpdateColumns(User{
Name: sql.NullString{"王十六", true}, Age: 36,
})
// UPDATE `users` SET `name`='王十六' WHERE id = 2

gorm中的更新的更多相关文章

  1. C#多线程开发中如何更新UI界面控件内容

    子线程不能修改UI线程的状态(比如文本框里面的内容). 解决的办法是写一个用来更新文本框内容的函数,然后在Worker线程里面通过BeginInvoke来利用delegate调用这个函数更新文本框. ...

  2. Android中动态更新ListView(转)

    在使用ListView时,会遇到当ListView列表滑动到最底端时,添加新的列表项的问题,本文通过代码演示如何动态的添加新的列表项到ListView中.实现步骤:调用ListView的setOnSc ...

  3. WPF中动态更新TextBlock文字中的超链接,文本

    1.------------------------------------------------------------------------- 修改超链接的文本文字: <TextBloc ...

  4. echarts异步数据加载(在下拉框选择事件中异步更新数据)

    接触echarts 大半年了,从不会到熟练也做过不少的图表,隔了一段时间没使用这玩意,好多东西真心容易忘了.在接触echarts这期间也没有总结什么东西,今天我就来总结一下如何在echart中异步加载 ...

  5. 从源码的角度看 React JS 中批量更新 State 的策略(下)

    这篇文章我们继续从源码的角度学习 React JS 中的批量更新 State 的策略,供我们继续深入学习研究 React 之用. 前置文章列表 深入理解 React JS 中的 setState 从源 ...

  6. 【mybatis】service层中一个方法中使用mybatis进行数据库的 多个修改操作,可能是update也可能是delete操作,但是sql语句命名执行并且在控制台打印出来了,但是数据库中未更新到数据【事务的问题】

    问题描述: service层中一个方法中使用mybatis进行数据库的 多个修改操作,可能是update也可能是delete操作,但是sql语句命名执行并且在控制台打印出来了,但是数据库中未更新到数据 ...

  7. 在Myeclipse中拷贝一个web项目,但是tomcat文件夹中没有更新,需要进行修改才能更新。

    1.在Myeclipse中拷贝一个web项目,但是tocat文件夹中没有更新,需要进行修改才能更新. 2.方法:右键这个工程,然后Properties->MyEclipse->Projec ...

  8. SqlServer中的更新锁(UPDLOCK和READPAST)

    UPDLOCK和READPAST,通过UPDLOCK和READPAST的结合我们能够解决许多问题,比如我当前项目中对于更新预约人数,则用到了UPDLOCK和READPAST,因为考虑到并发如果固定预约 ...

  9. Myabtis中批量更新update多字段

    在mybatis中批量更新多个字段 推荐使用如下操作: 方式1:在Dao层接口中: void updateBatch(@Param("list")List<Student&g ...

随机推荐

  1. ffmpeg、数字音频教程、JUCE、std::tuple

    下载网易云音乐的视频 https://yunyinyue.iiilab.com/ 模板教程: https://github.com/wuye9036/CppTemplateTutorial/blob/ ...

  2. 【LeetCode】359. Logger Rate Limiter 解题报告(C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 字典 日期 题目地址:https://leetcode ...

  3. light oj -1245 - Harmonic Number (II)

    先举个例子,假如给你的数是100的话,将100/2=50;是不是就是100除100-51之间的数取整为1: 100/3=33;100除50到34之间的数为2,那么这样下去到sqrt(100);就可以求 ...

  4. 晴天小猪历险记之Hill(Dijkstra优先队列优化)

    描述 这一天,他来到了一座深山的山脚下,因为只有这座深山中的一位隐者才知道这种药草的所在.但是上山的路错综复杂,由于小小猪的病情,晴天小猪想找一条需时最少的路到达山顶,但现在它一头雾水,所以向你求助. ...

  5. Java生成随机数的4种方式

    Random Random 类诞生于 JDK 1.0,它产生的随机数是伪随机数,也就是有规则的随机数.Random 使用的随机算法为 linear congruential pseudorandom ...

  6. Estimation of Non-Normalized Statistical Models by Score Matching

    目录 概 主要内容 方法 损失函数的转换 一个例子 Hyv"{a}rinen A. Estimation of Non-Normalized Statistical Models by Sc ...

  7. Webpack有哪些常见的Loader?他们是解决什么问题的?

    先来了解一下Loader,webpack是属于模块化方案,他能让任意类型的文件都能运行在浏览器中,怎么做到呢?这时就有了loader 定义: loader 用于对模块的源代码进行转换.loader 可 ...

  8. Microsoft HoloLens 开发(3): 全息图交互方式 - Gaze

    Gaze(凝视) 是 HoloLens 交互输入的第一种形式,告诉你 用户 在世界上的位置,并让你确定他们的意图. 1.Gaze的用途 作为一个 Mixed Reality 开发者,Gaze 可以做很 ...

  9. Python_string.Template的使用

    Template是python string提供的一个字符串模板功能.主要用于文本处理 from string import Template s = Template('$who 在 $do') t ...

  10. Pycharm_关闭PEP8函数名不能包含大写字母的规范

    屏蔽PEP8告警 全是小写字母,可能与以往的习惯不大一样,将这样的警告忽略的方法如下: File →Settings→Editor→Inspections→Python→PEP 8 naming co ...