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语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 👍…...

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官网 但…...

Linux 中的 grep 命令
Linux 中的 grep 命令是一个强大的文本搜索工具,它允许用户在文件中查找指定的文本模式,并将匹配的行打印出来。grep 是“Global Regular Expression Print”的缩写,它使用正则表达式来进行文本搜索,因此具有强大的灵活性和功能。…...

阶段五-Day03-Ajax
一、JavaWeb中路径的说明 1. JavaWeb中的路径 在JavaWeb中, 路径分为相对路劲和绝对路径两种: 相对路径: ./ 表示当前目录 ../ 表示当前文件所在目录的上一级目录 绝对路径: 完整的路径名 2. 在JavaWeb中/的不同意义 /斜杠如果被浏览器解析,得到的是 协议本地ip端口号…...

EPOLL单线程版本 基于reactor 的 httpserver文件下载 支持多个客户端同时处理
之前写了一个httpserver的问价下载服务器 如果有多个客户端请求过来只能串行处理必须得等当前的操作完成之后才会处理 另外还存在 文件大的时候 会出错 处理不了 原因就是 sendfile是在一个while循环中处理的 当调用send失败返回-1之后 就 结束了 而一般来讲 se…...

uniapp实现微信小程序隐私协议组件封装
uniapp实现微信小程序隐私协议组件封装。 <template><view class"diygw-modal basic" v-if"showPrivacy" :class"showPrivacy?show:" style"z-index: 1000000"><view class"diygw-dialog diygw-dialog-modal bas…...

【Node.js】NPM 和 package.json
NPM npm 是 Node.js 的包管理工具,基于命令行,用于安装、升级、移除、管理依赖项。 常用命令: npm init:初始化一个新的 npm 项目,创建 package.json 文件。(括号里为默认值) description&am…...

周总结【java项目】
项目进度: 学习了JavaFX,下载了sceneBuilder辅助工具构建窗口(目前建立了登陆,注册,忘记密码的界面),然后是学习了MySQL的连接,现在的项目是刚连上数据库; 下一步&…...

《深度不确定条件下的决策:从理论到实践》PDF
制定未来计划时需要预测变化,尤其是制定长期计划或针对罕见事件的计划时。当这些变化存在高度不确定性的时候,这种预期就变得越来越困难。 今天给大家介绍的这本《深度不确定条件下的决策:从理论到实践》正是解决以上问题的良方。完整书籍文…...

【MySQL】表的基础增删改查
前面我们已经知道怎么来创建表了,接下来就来对创建的表进行一些基本操作。 这里先将上次创建的表删除掉: mysql> use test; Database changedmysql> show tables; ---------------- | Tables_in_test | ---------------- | student | -----…...

第11章 Redis(二)
11.11 Redis 哨兵机制和集群有什么区别 难度:★★★ 重点:★★ 白话解析 前面的题目都是Redis的原理,接下来就是实际使用的问题了,首先Redis为了保证高可用,在微服务场景下必须是部署集群的,而Redis的集群部署通常就两种方式:主从和Redis Cluster。 参考答案 1、主从…...

mybatis配置entity下不同文件夹同类型名称的多个类型时启动springboot项目出现TypeException源码分析
记录问题:当配置了 mybatis.type-aliases-packagecom.runjing.erp.entity 配置项时,如果entity文件夹下存在不同子文件夹下的同名类型时,mybatis初始化加载映射时会爆出org.apache.ibatis.type.TypeException: The alias TestDemo…...