当前位置: 首页 > news >正文

golang gorm 增删改查以及使用原生SQL(以操作mysql为例)

gorm + mysql增删改查

model定义
package _caseimport "gorm.io/gorm"func init() {DB.Migrator().AutoMigrate(Teacher{}, Course{})
}
type Roles []stringtype Teacher struct {gorm.ModelName     string   `gorm:"size:256"`Email    string   `gorm:"size:256"`Salary   float64  `gorm:"scale:2;precision:7"`   // 指定小数部分宽度为2,列宽度为7. 列宽:【整数部分+小数部分的总长度】【不含小数点】Age      uint8    `gorm:"check:age>30"`Birthday int64    `gorm:"serializer:unixtime;type:time"`  // 反序列化方式 unixtime, 类型为timeRoles    Roles    `gorm:"serializer:json"`JobInfo  Job      `gorm:"embedded;embeddedPrefix:job_"`   // 嵌套字段, 嵌入字段的列名前缀job_JobInfo2 Job      `gorm:"type:bytes;serializer:gob"`      // 字节流类型,gob反序列化,go自己的序列化方法,跨语言项目的时候,不建议用
}type Job struct {Title    stringLocation string
}type Course struct {gorm.ModelName   string  `gorm:"size:256"`Price  float64 `gorm:"scale:2;precision:7"`UserID uint    `gorm:"type:int"`
}
数据库连接并设置连接池
package _caseimport ("gorm.io/driver/mysql""gorm.io/gorm""gorm.io/gorm/logger""log""time"
)var DB *gorm.DBvar dsn = "root:123456@tcp(10.74.18.61:3306)/mydb?charset=utf8mb4&parseTime=True&loc=Local"func init() {var err error// 每次调用返回的都是DB对象,这是支持链式调用的DB, err = gorm.Open(mysql.New(mysql.Config{DSN: dsn,DefaultStringSize: 256,}), &gorm.Config{Logger: logger.Default.LogMode(logger.Info),//开启预编译,提高后续调用速度//开启预编译的情况下,不支持嵌套事务PrepareStmt: true,})if err != nil {log.Println(err)return}setPool(DB)
}// 连接池设置
func setPool(db *gorm.DB) {sqlDB, err := db.DB()if err != nil {log.Println(err)return}// 连接存活最大时长sqlDB.SetConnMaxLifetime(time.Hour)// 最大空闲连接数sqlDB.SetMaxIdleConns(5)// 最大连接打开数sqlDB.SetMaxOpenConns(10)}

假数据定义

var teacherTemp = Teacher{Name: "kk",Age: 40,Salary: 1234.22,Email: "kk123@qq.com",Birthday: time.Now().Unix(),Roles: Roles{"普通用户", "讲师"},JobInfo: Job{Title: "教授",Location: "九龙湖",},JobInfo2: Job{Title: "教授",Location: "九龙湖",},
}
插入数据
  • 插入一条/多条记录
t1 := teacherTemp 
res := DB.Create(&t) // 指针传入
  • 正向选择, 选择某些字段插入 【gorm model里的不包含】
t1 := teacherTemp
res = DB.Select("name", "age").Create(&t1)
  • 反向选择, 排除某些字段插入(忽略大小写
t2 := teacherTemp
res = DB.Omit("email", "Birthday").Create(&t2)
  • 批量,按batchsize插入
var teachers = []Teacher{{Name: "qq", Age: 50}, {Name: "pp", Age: 60}, {Name: "gg", Age: 55}, {Name: "mm", Age: 56}}
DB.CreateInBatches(teachers, len(teachers))  // 或者直接DB.Create(teachers)
  • 查找第一个匹配的记录并返回,若无匹配记录则插入
t3 := teacherTemp
t3.Name = "oo"
out := Teacher{}
res = DB.Attrs(t3).FirstOrCreate(&out, Teacher{Name: "oo"})
删除数据

gorm采用的是软删除,删除语句为update,去更新delete_at字段

  • 根据ID删除
DB.Delete(&Teacher{Model: gorm.Model{ID: 9}})

gorm输出语句(软删除)

 UPDATE `teachers` SET `deleted_at`='2023-10-09 18:51:43.901' WHERE `teachers`.`id` = 9 AND `teachers`.`deleted_at` IS NULL
  • 根据条件删除, 批量删除
DB.Where("name like ?", "yuan*").Delete(&Teacher{})
DB.Delete(&Teacher{}, []int{3,4,5,})
  • 根据主键删除(主键不一定是gorm.Model的ID)
DB.Delete(&Teacher{}, 1)
DB.Delete(&Teacher{}, []int{3,4,5,})
更新数据
  • 全部更新
teacher := Teacher{}
DB.First(&teacher)
// 更新
teacher.Age = 66
teacher.Name = "wang"
// 更新所有 save 会将所有字段保存到数据库, 无论字段有没有被改
DB.Save(teacher)
  • 更新单行数据某个列
DB.Model(&Teacher{}).Where("id = ?", teacher.ID).Update("name", "yuan")
  • 通过model指定条件更新, 只能指定ID
DB.Model(&Teacher{Model:gorm.Model{ID: teacher.ID}}).Update("name", "yuan")
  • 更新单行多个列
// 更新单行多个列 结构体方式
DB.Model(&Teacher{}).Where("id = ?", teacher.ID).Updates(Teacher{Name: "updatayuan", Age: 40})
// 更新单行多个列 map方式
DB.Model(&Teacher{}).Where("id = ?", teacher.ID).Updates(map[string]interface{}{"name": "updateY", "age": 40})
  • 批量更新 多行数据
DB.Model(&Teacher{}).Where("age > ?", 60).Updates(Teacher{Email: "update@qq.com"}) // 用map也行
  • 选定/排除某些字段更新
// 选定更新某些字段
DB.Model(&Teacher{}).Where("id = ?", 5).Select("name", "age").Updates(teacher)
// 排除某些字段 更新
DB.Model(&Teacher{}).Where("id = ?", 5).Omit("name", "age").Updates(teacher)
查询
简单查询
  • 单记录查询
func GetOnce() {t := Teacher{}// 查询一条// 获取主键排序第一条DB.First(&t)// 无排序规则 取第一条t = Teacher{}DB.Take(&t)// 主键排序最后一条t = Teacher{}DB.Last(&t)//查询结果填充到集合中result := map[string]interface{}{}// 可能会有特殊类型不好处理,无法完成类型转换,可以忽略一些字段DB.Model(&Teacher{}).Omit("Birthday", "Roles", "JobInfo2").First(&result)// 基于表名 查询记录result = map[string]interface{}{}DB.Table("teachers").Take(&result)}
  • 根据字符串条件获取记录
func GetByStrCond() {t := Teacher{}var teaches []TeacherDB.Find(&teaches, "name IN ?", []string{"yuan", "oo", "gg"})DB.Where("name = ?", "gg").First(&t)DB.Where("name IN ?", []string{"yuan", "oo"}).Find(&teaches)
}
  • 通过结构体或集合指定条件查询
func GetByStructOrMapCond() {var teachers []Teachert := Teacher{}//structDB.Find(&teachers, Teacher{Name: "oo", Age: 40})// mapDB.Find(&teachers, map[string]interface{}{"Name": "gg", "Age": 40})DB.Where(Teacher{Name: "yuan", Age: 40}).First(&t)DB.Where(map[string]interface{}{"Name": "qq", "Age": 40}).Find(&teachers)DB.Where([]int{10, 11, 12}).Find(&teachers)//指定查询条件使用的字段DB.Where(Teacher{Name: "cc"}, "name", "age").Find(&teachers)
}
复合查询
  • 复杂条件查询
var teachers []Teacher
// 复合查询 offset为跳过几个记录,分页会用
DB.Where(DB.Where("name = ?", "yuan").Or("name = ?", "oo")).
Where("age > ?", 40).Order("id desc").Offset(1).Limit(10).Find(&teachers)// 查询返回行rows
rows, err := DB.Model(&Teacher{}).Select("id", "name").Where(DB.Where("name in ?", []string{"oo", "qq"})).
Order("id desc").Offset(1).Limit(10).Rows()if err != nil {log.Fatal(err)
}
defer rows.Close()
// 扫描row
for rows.Next() {id := 0name := ""err = rows.Scan(&id, &name)if err != nil {continue}fmt.Println(id, name)
}
  • 分组聚合
// 分组聚合
type Result struct {Count intAge   int
}
list := []Result{}
DB.Model(&Teacher{}).Select("count(*) as count", "age").Not("name = ?", "yuan").
Group("age").Having("count > ?", 2).Rows()fmt.Println(list)
// 根据年龄分组,过滤掉name为yuan的数据,保留对应分组count数大于2的结果
rows2, err := DB.Model(&Teacher{}).Select("count(*) as count", "age").Not("name = ?", "yuan").
Group("age").Having("count > ?", 2).Rows()
if err != nil {log.Fatal(err)
}
defer rows2.Close()for rows2.Next() {count := 0age := 0err = rows2.Scan(&count, &age)if err != nil {continue}fmt.Println(count, age)
}
使用原生SQL查询

基本exec和raw就够用了

func NativeSql() {var teacher Teachervar list []Teacher//查询DB.Raw("select id,name,age from teachers where name = ?", "yuan").Scan(&teacher)fmt.Println(teacher)DB.Raw("select id,name,age from teachers where name = ?", "yuan").Scan(&list)fmt.Println(list)teacher = Teacher{}DB.Raw("select id,name,age from teachers where name = ?", "yuan").Find(&teacher)fmt.Println(teacher)//更新res := DB.Exec("update teachers set age = @age where name = @name", sql.Named("age", 22), sql.Named("name", "yuan"))fmt.Println(res.RowsAffected, res.Error)}

相关文章:

golang gorm 增删改查以及使用原生SQL(以操作mysql为例)

gorm mysql增删改查 model定义 package _caseimport "gorm.io/gorm"func init() {DB.Migrator().AutoMigrate(Teacher{}, Course{}) } type Roles []stringtype Teacher struct {gorm.ModelName string gorm:"size:256"Email string gorm:&q…...

代码随想录 单调栈part2

503. 下一个更大元素 II 给定一个循环数组 nums ( nums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素 。 数字 x 的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数…...

详解利用高斯混合模型拆解多模态分布 + 精美可视化

文章目录 一、前言二、主要内容三、总结🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 一、前言 本文旨在介绍如何利用高斯混合模型(Gaussian Mixture Models,简称 GMMs)将一维多模态分布拆分为多个分布。作为统计 / / /机器学习领域常用的概率模型...

排序算法之【归并排序】

📙作者简介: 清水加冰,目前大二在读,正在学习C/C、Python、操作系统、数据库等。 📘相关专栏:C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…...

Qt中QTimer定时器的用法

Qt中提供了两种定时器的方式一种是使用Qt中的事件处理函数,另一种就是Qt中的定时器类QTimer。 使用QTimer类,需要创建一个QTimer类对象,然后调用其start()方法开启定时器,此后QTimer对象就会周期性的发出timeout()信号。 1.QTimer…...

vue-组件定义注册使用

vue组件使用的步骤 定义组件注册组件使用组件 定义组件 Vue.extend(options) 其中options和new Vue(options)出入的options对象几乎一样,但是也有不同。 创建 el不用写—最终所有组件需要经过一个vm的管理,由vm的el决定服务哪个容器。 data必须写成函…...

斑馬打印機打印中文

创建项目 首先說一下,本文章是借鉴了其他大佬的文章,然后我记录一下的文章。 首先创建好一个.net framework的winform项目。 这里面主要用到两个库文件: Fnthex32.dll、LabelPrint.dll。 Fnthex32这个有8位参数和9位参数的,我这…...

(一)Apache log4net™ 手册 - 介绍

0、相关概念 Log4j 几乎每个大型应用程序都包含自己的日志记录或跟踪 API。根据这一规则,E.U. SEMPER 🌹项目决定编写自己的跟踪 API。那是在 1996 年初。经过无数次的增强、几个化身和大量的工作,API 已经发展成为 log4j —— 一个流行的 Ja…...

基于Java的民宿管理系统设计与实现(源码+lw+部署文档+讲解等)(民宿预约、民宿预订、民宿管理、酒店预约通用)

文章目录 前言具体实现截图论文参考详细视频演示代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技…...

039:mapboxGL更换地图上的鼠标样式

第039个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中更换地图上的鼠标的样式。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码(共74行)相关API参考:专栏目标示例效果 配置方式 1)查看基础设置:htt…...

【云原生】K8S对外服务之Ingress

目录 一、Ingress 简介1.1Ingress 组成1.3Ingress-Nginx 工作原理 二、部署 nginx-ingress-controller2.1部署ingress-controller Pod及相关资源2.2ingress 暴露服务的方式2.3 采用方式二:DaemonSetHostNetworknodeSelector 三、采用方式二:DeploymentNo…...

分布式锁如何实现

分布式是现在的比较主流的技术,常常和微服务一起出现。那么对于多个实例之间,如何证分布式系统中多个进程或线程同步访问共享资源呢?我们其实一想到的就是锁,我们在java里边有 synchronized, 在python里有lock,但是这个…...

Mysql存储-EAV模式

Mysql存储-EAV模式 最近又又又搞一点新东西,要整合不同业务进行存储和查询,一波学习过后总结了一下可扩展性MAX的eav模式存储。 在eav这里的数据结构设计尤为关键,需要充分考虑你需要使用的字段、使用场景,当数据结构设计完成后便…...

全局变量报错:\Output\STM32.axf: Error: L6218E: Undefined symbol

全局变量报错: .\Output\STM32.axf: Error: L6218E: Undefined symbol key_num (referred from main.o). 这里只说全局变量哦,这是因为你在调用的.c文件里 把定义写在了函数里面,写函数外面就没事了 改为: .h的声明文件根本不用写…...

算法错题簿(持续更新)

自用算法错题簿,按算法与数据结构分类 python1、二维矩阵:记忆化搜索dp2、图论:DFS3、回溯:129612964、二叉树:贪心算法5、字符串:记忆化搜索6、01字符串反转:结论题7、二进制数:逆向…...

基于Springboot实现疫情网课管理系统项目【项目源码+论文说明】

基于Springboot实现疫情网课管理系统演示 摘要 随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势;对于疫情网课管理系统当然也不能排除在外,随着网络技术的不断成熟,带动了疫情…...

Linux文件与目录的增删改查

一、增 1、mkdir命令 作用: 创建一个新目录。 格式: mkdir [选项] 要创建的目录 常用参数: -p:创建目录结构中指定的每一个目录,如果目录不存在则创建,如果目录已存在也不会被覆盖。 用法示例&a…...

JVM的内存模型

一、JVM的内存模型 1.1、目标 内存模型是用来描述JVM内部的内存结构和内存管理的模型。它定义了JVM在运行Java程序时所需要的各种内存区域,以及每个内存区域的作用和特点。 1.2、结构划分 1.2.1、栈 每个线程在执行Java方法时会创建一个栈帧(Stack …...

数据采集项目之业务数据(三)

1. Maxwell框架 开发公司为Zendesk公司开源,用java编写的MySQL变更数据抓取软件。内部是通过监控MySQL的Binlog日志,并将变更数据以JSON格式发送到Kafka等流处理平台。 1.1 MySQL主从复制 主机每次变更数据都会生成对应的Binlog日志,从机可…...

vuedraggable影响点击事件的解决办法

在工作中有很多场景需要针对广告、商品、信息推广等进行一个排序,或者对展示的顺序做出调整,方便放用户第一眼看到自己感兴趣的信息,因此避免不了需要用到排序的插件,这里以vue为例子,采用的插件是vuedraggable,这个插件针对于排序的功能相对完善,官网地址:vuedraggable官网 但…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

在树莓派上添加音频输入设备的几种方法

在树莓派上添加音频输入设备可以通过以下步骤完成&#xff0c;具体方法取决于设备类型&#xff08;如USB麦克风、3.5mm接口麦克风或HDMI音频输入&#xff09;。以下是详细指南&#xff1a; 1. 连接音频输入设备 USB麦克风/声卡&#xff1a;直接插入树莓派的USB接口。3.5mm麦克…...

Ubuntu系统复制(U盘-电脑硬盘)

所需环境 电脑自带硬盘&#xff1a;1块 (1T) U盘1&#xff1a;Ubuntu系统引导盘&#xff08;用于“U盘2”复制到“电脑自带硬盘”&#xff09; U盘2&#xff1a;Ubuntu系统盘&#xff08;1T&#xff0c;用于被复制&#xff09; &#xff01;&#xff01;&#xff01;建议“电脑…...

DAY 26 函数专题1

函数定义与参数知识点回顾&#xff1a;1. 函数的定义2. 变量作用域&#xff1a;局部变量和全局变量3. 函数的参数类型&#xff1a;位置参数、默认参数、不定参数4. 传递参数的手段&#xff1a;关键词参数5 题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一…...