GORM 与 MySQL(一)

news2024/11/27 23:47:43

GORM 操作 Mysql 数据库(一)

温馨提示:以下关于 GORM 的使用,是基于 Gin 框架的基础上,如果之前没有了解过 Gin 可能略微困难。

GORM 介绍

GORM 是 Golang 的一个 orm 框架。简单说,ORM 就是通过实例对象的语法,完成关系型
数据库的操作的技术,是"对象-关系映射"(Object/Relational Mapping) 的缩写。使用 ORM
框架可以让我们更方便的操作数据库。

GORM 官方支持的数据库类型有: MySQL, PostgreSQL, SQlite, SQL Server。

GORM 特性

  • 全功能 ORM
  • 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
  • Create,Save,Update,Delete,Find 中钩子方法
  • 支持 Preload、Joins 的预加载
  • 事务,嵌套事务,Save Point,Rollback To Saved Point
  • Context、预编译模式、DryRun 模式
  • 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进
    行 CRUD
  • SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
  • 复合主键,索引,约束
  • Auto Migration
  • 自定义 Logger
  • 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
  • 每个特性都经过了测试的重重考验
  • 开发者友好

GORM 前置

安装

如果使用 go mod 管理项目的话可以忽略此步骤

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

连接数据库

在 models 下面新建 core.go ,建立数据库链接

package modles

import (
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

var db *gorm.DB
var err error

func init() {
	dsn := "root:123456789@tcp(127.0.0.1:3306)/gorm_test?charset=utf8mb4&parseTime=True&loc=Local"

	// Globally mode
	db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic(err)
	}
}

定义操作模型

在实际项目中定义数据库模型注意以下几点:

1、结构体的名称必须首字母大写 ,并和数据库表名称对应。

例如:表名称为 user 结构体名称定义成 User,表名称为 article_cate 结构体名称定义成 ArticleCate

2、结构体中的字段名称首字母必须大写,并和数据库表中的字段一一对应。

例如:下面结 构体中的 Id 和数据库中的 id 对应,Username 和数据库中的 username 对应,Age 和数据库中 的 age 对应,Email 和数据库中的 email 对应,AddTime 和数据库中的 add_time 字段对应。

3、默认情况表名是结构体名称的复数形式。

如果我们的结构体名称定义成 User,表示这个 模型默认操作的是 users 表。

4、我们可以使用结构体中的自定义方法 TableName 改变结构体的默认表名称,如下:

func (User) TableName() string { 
  return "user"
}

表示把 User 结构体默认操作的表改为 user 表。

定义 User 模型:

package modles

type User struct { 
	// 默认表名是 users
	Id int
	Username string
	Age int1
	Email string
	AddTime int
}

func(User) TableName() string {
	return "user"
}

gorm.Model 模型

GORM 定义一个 gorm.Model 结构体,其包括字段 IDCreatedAtUpdatedAtDeletedAt

type Model struct {
ID uint `gorm:"primaryKey"` 
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}

GORM CRUD

注意:我们在关键词之前加上 DEBUG 方法可以获取执行的 SQL 语句。

增加

我们一般使用 Create 方法构建,增加成功后会返回刚才增加的记录。

func (con UserController) Add(c *gin.Context) {
	// 单数据
	user := models.User{
		UserName: "ypb",
		Age:      20,
		Email:    "ychag@example.com",
		AddTime:  int(time.Now().Unix()),
	}

	// 批量数据
	users := []*models.User{
		{UserName: "yxc", Age: 20, Email: "ychag@example.com", AddTime: int(time.Now().Unix())},
		{UserName: "zmz", Age: 20, Email: "zmzag@example.com", AddTime: int(time.Now().Unix())},
	}

	result := models.DB.Create(&users) // 通过指针创建
	if result.RowsAffected > 1 {
		fmt.Println(user.Id)
	}

	fmt.Println(result.RowsAffected)
	fmt.Println(user.Id)
	c.String(200, "add ok")
}

查找

GORM 提供了 FirstTakeLastFind 方法,以便从数据库中检索对象。

不指定条件查询
func (con UserController) Get(c *gin.Context) {
	user := models.User{}

	// First 获取第一条记录(主键升序)
	models.DB.Debug().First(&user)
	// SELECT * FROM `user` ORDER BY `user`.`id` LIMIT 1
	fmt.Println(user.Id)

	// Last 获取最后一条记录(主键降序)
	models.DB.Debug().Last(&user)
	fmt.Println(user.Id)
	// SELECT * FROM `user` WHERE `user`.`id` = 1 ORDER BY `user`.`id` DESC LIMIT 1

	// Find 获取所有记录
	users := []models.User{}
	models.DB.Debug().Find(&users)
	//SELECT * FROM `user`

	c.JSON(200, gin.H{
		"message": "get ok",
		"result":  users,
	})
}
指定条件查询
func (con UserController) GetByCondition(c *gin.Context) {
	user := models.User{}

	// Where 指定查询条件
	models.DB.Debug().Where("user_name = ?", "yxc").First(&user)
	//  SELECT * FROM `user` WHERE user_name = 'yxc' ORDER BY `user`.`id` LIMIT 1
	c.JSON(200, gin.H{
		"message": "get ok",
		"result":  user,
	})
}

修改

字段条件查询修改
func (con UserController) Update(c *gin.Context) {
	// 首先获取数据
	user := models.User{Id: 1}
	models.DB.Debug().Find(&user)
	//  SELECT * FROM `user` WHERE `user`.`id` = 1

	// 然后更新数据
	user.UserName = "haha"
	user.Age = 22
	models.DB.Debug().Save(&user)
	// UPDATE `user` SET `user_name`='haha',`age`=22,`email`='ychag@example.com',`add_time`=1708047687 WHERE `id` = 1
	c.String(200, "update ok")
}

where 条件查询修改
func (con UserController) UpdateByCondition(c *gin.Context) {
	// Where 条件更新单列数据
	models.DB.Debug().Model(&models.User{}).Where("id = ?", 1).Update("age", 15)
	// UPDATE `user` SET `age`=15 WHERE id = 1

	// Where 条件更新多列数据
	var users []models.User
	models.DB.Debug().Model(&users).Where("user_name = ?", "yxc").Updates(models.User{UserName: "yxc", Age: 22})
	// UPDATE `user` SET `user_name`='yxc',`age`=22 WHERE user_name = 'yxc'
	c.String(200, "update ok")
}

删除

删除单行数据:

func (con UserController) Delete(c *gin.Context) {
	// Where 条件删除单条数据
	models.DB.Debug().Where("user_name = ?", "haha").Delete(&models.User{})
	// DELETE FROM `user` WHERE user_name = 'haha'
}

删除所有数据:

func (con UserController) DeleteAll(c *gin.Context) {
	users := []models.User{}
	models.DB.Debug().Where("id > ?", 0).Delete(&users)
	//  SELECT * FROM `user` WHERE id > 0
	c.JSON(200, gin.H{
		"message": "delete ok",
	})
}

GORM 查询语句详解

where 及 操作符

func (a ArticleController) Get(c *gin.Context) {
	article := &[]models.Article{}
	//  < 小于号, 选择所有id小于3的文章
	models.DB.Debug().Where("id < ?", 3).Find(&article)
	//  SELECT * FROM `articles` WHERE id < 3 AND `articles`.`deleted_at` IS NULL

	// > 大于号, 选择所有id大于5的文章
	var id = 5
	models.DB.Debug().Where("id > ?", id).Find(&article)
	// SELECT * FROM `articles` WHERE id > 5 AND `articles`.`deleted_at` IS NULL

	// AND 操作符, 选择所有id大于1且小于5的文章
	models.DB.Debug().Where("id > ? and id < ?", 1, 5).Find(&article)
	//  SELECT * FROM `articles` WHERE (id > 1 AND id < 5) AND `articles`.`deleted_at` IS NULL

	// in 操作符, 选择所有id大于2且小于5的文章
	models.DB.Debug().Where("id in ?", []int{3, 4}).Find(&article)
	//SELECT * FROM `articles` WHERE id in (3,4) AND `articles`.`deleted_at` IS NULL

	// like 操作符, 选择 文章标题含 go 的文章
	models.DB.Debug().Where("title like ?", "%go%").Find(&article)
	// SELECT * FROM `articles` WHERE title like '%go%' AND `articles`.`deleted_at` IS NULL

	// between and 操作符, 选择文章id在 1 到 5 之间的文章
	models.DB.Debug().Where("id between ? and ?", 1, 5).Find(&article)
	// SELECT * FROM `articles` WHERE (id between 1 and 5) AND `articles`.`deleted_at` IS NULL

	// or 操作符, 选择文章id在 1 到 5 之间的文章或 id 等于 6 的文章
	models.DB.Debug().Where("id between ? and ? or id = ?", 1, 5, 6).Find(&article)
	//SELECT * FROM `articles` WHERE (id between 1 and 5 or id = 6) AND `articles`.`deleted_at` IS NULL
	models.DB.Debug().Where("id between ? and ?", 1, 5).Or("id = ?", 6).Find(&article)
	//SELECT * FROM `articles` WHERE ((id between 1 and 5) OR id = 6) AND `articles`.`deleted_at` IS NULL

	c.JSON(200, gin.H{
		"success": true,
		"result":  article,
	})
}

指定字段查询

func (a ArticleController) GetOne(c *gin.Context) {
	article := &[]models.Article{}

	// 查询文章的id 和 title
	models.DB.Debug().Select("id, title").First(&article)
	c.JSON(200, gin.H{
		"success": true,
		"result":  article,
	})
}

排序

func (a ArticleController) GetOne(c *gin.Context) {
	article := &[]models.Article{}

	// 按 ID 降序排序
	models.DB.Debug().Order("id desc").Find(&article)
	// SELECT * FROM `articles` WHERE `articles`.`deleted_at` IS NULL ORDER BY id desc

	// 按 ID 升序排序 按 author_id 降序排序
	models.DB.Debug().Order("id asc, author_id desc").Find(&article)
	// SELECT * FROM `articles` WHERE `articles`.`deleted_at` IS NULL ORDER BY id asc, author_id desc
	c.JSON(200, gin.H{
		"success": true,
		"result":  article,
	})
}

Limit, Offset

func (a ArticleController) GetOne(c *gin.Context) {
	article := &[]models.Article{}

	// 查询ID大于1的文章, 限制1条数据 (随机一条)
	models.DB.Debug().Where("id > ?", 1).Limit(1).Find(&article)
	// SELECT * FROM `articles` WHERE id > 1 AND `articles`.`deleted_at` IS NULL LIMIT 1

	// 实现 跳过一条数据查询2条数据 (分页)
	models.DB.Debug().Where("id > ?", 1).Offset(1).Limit(1).Find(&article)
	// SELECT * FROM `articles` WHERE id > 1 AND `articles`.`deleted_at` IS NULL LIMIT 1 OFFSET 1
	c.JSON(200, gin.H{
		"success": true,
		"result":  article,
	})
}

获取总数

func (a ArticleController) GetSum(c *gin.Context) {
	article := &[]models.Article{}

	var sum int64
	// 获取author_id等于1的文章的数量
	models.DB.Debug().Where("author_id = ?", 1).Find(&article).Count(&sum)
	//SELECT count(*) FROM `articles` WHERE author_id = 1 AND `articles`.`deleted_at` IS NULL

	c.JSON(200, gin.H{
		"success": true,
		"result":  article,
	})
}

获取不同值

func (a ArticleController) GetDistinct(c *gin.Context) {
	article := &[]models.Article{}

	// 选择不同的 title
	models.DB.Debug().Distinct("title").Find(&article)
	// SELECT DISTINCT `title` FROM `articles` WHERE `articles`.`deleted_at` IS NULL
	c.JSON(200, gin.H{
		"success": true,
		"result":  article,
	})
}

Scan

Scan 可以将结果绑定到一个结构体上。

type Result struct {
	AuthorId int
	Title    string
}

func (a ArticleController) GetScan(c *gin.Context) {
	var result []Result
	//models.DB.Table("articles").Select("author_id, title").Scan(&result)
	models.DB.Raw("SELECT author_id, title FROM articles").Scan(&result)
	fmt.Println(result)
}

原生 SQL 和 生成器

1、使用原生 sql 删除 user 表中的一条数据

result := models.DB.Exec("delete from user where id=?", 3) 
fmt.Println(result.RowsAffected)

2、使用原生 sql 修改 user 表中的一条数据

result := models.DB.Exec("update user set username=? where id=2", "哈哈") 
fmt.Println(result.RowsAffected)

3、查询 uid = 2 的数据

var result models.User
models.DB.Raw("SELECT * FROM user WHERE id = ?", 2).Scan(&result) 
fmt.Println(result)

4、查询 User 表中所有的数据

var result []models.User
models.DB.Raw("SELECT * FROM user").Scan(&result) 
fmt.Println(result)

5、统计 user 表的数量

var count int
row := models.DB.Raw("SELECT count(1) FROM user").Row(&count ) 
row.Scan(&count)

结尾

本次我们了解了 GORM 的基本用法,主要设计到对一个表的操作。但是在实际的业务中,我们往往需要从多张表获取数据。

下次,我们将去了解 GORM 中多表操作。

下次见。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

京东工业优选商品详情API接口:解锁高效工业采购新体验

京东工业优选的商品详情API接口&#xff0c;允许开发者通过程序化的方式&#xff0c;快速获取平台上的商品详细信息。这些详细信息包括但不限于商品名称、价格、规格、库存、图片、评价等&#xff0c;为企业提供全方位的商品信息查询服务。 二、API接口的主要功能 实时查询&a…

如何查看慢查询

4.2 如何查看慢查询 知道了以上内容之后&#xff0c;那么咱们如何去查看慢查询日志列表呢&#xff1a; slowlog len&#xff1a;查询慢查询日志长度slowlog get [n]&#xff1a;读取n条慢查询日志slowlog reset&#xff1a;清空慢查询列表 5、服务器端优化-命令及安全配置 安…

DDR4 新功能介绍

DDR4(第四代双倍数据率同步动态随机存取内存)相较于其前代DDR3,引入了一些新的功能和改进,这些新功能有助于提高内存的性能、降低功耗以及增强系统的可靠性,包括VPP、DBI(Data Bus Inversion,数据总线翻转)和DMI(与LPDDR4相关)。以下是对这些功能的简要说明: 更高的…

Stable Diffusion:AI绘画的新纪元

摘要&#xff1a; Stable Diffusion&#xff08;SD&#xff09;作为AI绘画领域的新星&#xff0c;以其开源免费、强大的生成能力和高度的自定义性&#xff0c;正在引领一场艺术与技术的革命。本文旨在为读者提供Stable Diffusion的全面介绍&#xff0c;包括其原理、核心组件、安…

嵌入式学习——C语言基础——day15

1. 段错误调试 1.1 打印法 在可能出现错误的位置加入打印,前一句能够打印出来,后一句打印不出来,问题就可以定位到两次打印中间的代码 1.2 gbd调试法 1. 编译代码时加入-g选项 gcc filename.c -g 2. 使用gdb调试生成的代码 gdb a.out 3. gdb调试命令 l 查看…

突然断电,瀚高数据库启动失败

服务器临时断电后&#xff0c;数据库启动不起来 ps -ef|grep postgres 进到数据库的data目录下看下ls 看下 查看临时文件&#xff1a; ls -la /tmp 把这两个5866的文件改个名字张老师 加个bak就行 改完了pg_ctl start起一下

六、文件查找

一、文件查找 1.查找文件内容 ​ 命令&#xff1a;grep keywords /dir_path/filename 2.查找系统命令 ​ 命令&#xff1a;which command 3.查找命令及配置文件位置 ​ 命令&#xff1a;whereis command 4.find查找 ​ find $find_path -name|-type|-perm|-size|-atime…

HarmonyOS实战开发教程-如何开发一个2048游戏

今天为大家分享的是2048小游戏&#xff0c;先看效果图&#xff1a; 这个项目对于新手友友来说可能有一点难度&#xff0c;但是只要坚持看完一定会有收获。因为小编想分享的并不局限于ArkTs语言&#xff0c;而是编程思想。 这个游戏的基本逻辑是初始化一个4乘4的数组&#xff…

跟TED演讲学英文:4 pillars of college success in science by Freeman Hrabowski

4 pillars of college success in science Link: https://www.ted.com/talks/freeman_hrabowski_4_pillars_of_college_success_in_science Speaker: Freeman Hrabowski Date: February 2013 文章目录 4 pillars of college success in scienceIntroductionVocabularyTranscr…

休斯《公共管理导论》第5版/考研真题解析/章节题库

第一部分 考研真题精选 一、概念题二、简答题三、论述题四、案例分析题第二部分 章节题库 第1章 一个变革的时代第2章 政府的角色第3章 传统的公共行政模式第4章 公共管理第5章 公共政策第6章 治 理第7章 问 责第8章 利害关系人和外部环境第9章 管制、外包和公共企…

有哪些软件可以使用云渲染?

随着技术的发展&#xff0c;云渲染已成为动画制作人员与设计师重要的渲染助手。它可结合云端强大的计算机能力&#xff0c;帮助渲染人员高速的完成渲染任务&#xff0c;大幅度节省时间和本地计算资源。它们以用户友好的界面、强大灵活的渲染能力&#xff0c;满足了各类专业渲染…

鸿蒙内核源码分析(进程通讯篇) | 九种进程间通讯方式速揽

进程间为何要通讯 ? 鸿蒙内核默认支持 64个进程和128个任务&#xff0c;由进程池和任务池统一管理.内核设计尽量不去打扰它们&#xff0c;让各自过好各自的日子&#xff0c; 但大家毕竟在一口锅里吃饭&#xff0c; 不可能不与外界联系&#xff0c; 联系就得有渠道&#xff0c…

【进程终止】退出信号 | 三种退出情况 | 如何进程终止returnexit_exit

目录 退出码 退出信号 进程终止情况3 如何进程终止 return退出 库函数exit 系统调用函数_exit ​exit和_exit的区别缓冲区 exit _exit 退出码 回顾上篇 代码跑完&#xff0c;结果正确&#xff08;退出码为0&#xff09;代码跑完&#xff0c;结果不正确&#xff08;退…

选择器、pxcook软件、盒子模型

结构伪类选择器 定义&#xff1a;根据结构的元素关系来查找元素。 <title>Document</title><style>li:first-child{color:aqua ;}li:last-child{color: aqua;}li:nth-child(3){color: aqua;}</style> </head> <body><ul><li>…

端口被其他进程占用:OSError: [Errno 98] Address already in use

一、问题描述 错误提示端口号正在被使用 二、解决办法 1.使用 lsof 命令&#xff0c;列出所有正在监听&#xff08;即被绑定&#xff09;的网络连接&#xff0c;包括它们所使用的端口号 sudo lsof -i -P -n | grep LISTEN 2.解绑被绑定的端口号 根据 netstat 或 lsof 命令…

C#修改默认参数settings文件

右击项目在设置中进行修改&#xff1a; 千万不要在这里改。 如果要在自己的项目里添加这个文件&#xff0c;首先新建个文件夹&#xff0c;然后添加.setting文件&#xff0c;然后再像上面说的那样添加属性。

Ansible自动化工具模块调用与playbook编写

目录 一、Ansible工作机制与特点 &#xff08;一&#xff09;Ansible工作机制 1. 初始化与配置 2. 编写Playbook 3. 调用模块 4. 加密敏感数据 5. 执行Playbook 6. 收集执行结果 7. 错误处理与回滚 8. 反馈与报告 &#xff08;二&#xff09;Ansible 的主要特点包括…

BUUCTF [极客大挑战 2019]EasySQL 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; [极客大挑战 2019]EasySQL 1 密文&#xff1a; 解题思路&#xff1a; 1、根据题目提示&#xff0c;并且网站也存在输入框&#xff0c;尝试进行SQL注入。 首先&#xff0c;判断提交方式&#xff0c;随机输入数据…

力扣刷题--数组--第二天

今天仍然做二分查找相关的题目。先来回顾一下二分查找的方法和使用的条件。二分查找是在数组中查找目标值的一种方法&#xff0c;通过边界索引确定中间索引&#xff0c;判断中间索引处的元素值和目标值的大小&#xff0c;来不断缩小查找区间。使用二分查找有如下一些限制&#…

PXE批量安装

系统装机的三种引导方式 u盘光盘网络装机 光盘&#xff1a; 1.类似于usb模式 2.刻录模式 系统安装过程 加载boot loader Boot Loader 是在操作系统内核运行之前运行的一段小程序。通过这段小程序&#xff0c;我们可以初始化硬件设备、建立内存空间的映射图&#xff0c;从…