Go语言之GORM框架(三)——Hook(钩子)与Gorm的高级查询

Hook(钩子)

和我们在gin框架中讲解的Hook函数一样,我们也可以在定义Hook结构体,完成一些操作,相关接口声明如下:

type CreateUser interface {    //创建对象时使用的Hook
	BeforeCreate() error
	BeforeSave() error
	AfterCreate() error
	AfterSave() error
}


type UpdateUser interface {
	BeforeUpdate() error
	BeforeSave() error
	AfterUpdate() error
	AfterSave() error
}

type DeleteUser interface {
	BeforeDelete() error
	AfterDelete() error
}

type FindUser interface {
	AfterFind() error
}

我们可以根据自己的需求来订制我们所需要的Hook函数,示例:

func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
  u.UUID = uuid.New()

  if !u.IsValid() {
    err = errors.New("can't save invalid data")
  }
  return
}

func (u *User) AfterCreate(tx *gorm.DB) (err error) {
  if u.ID == 1 {
    tx.Model(u).Update("role", "admin")
  }
  return
}

注意

  • Hook函数在执行过程的执行时间有规定的时间,以创建对象的Hook为例:
// 开始事务
BeforeSave
BeforeCreate
// 关联前的 save
// 插入记录至 db
// 关联后的 save
AfterCreate
AfterSave
// 提交或回滚事务

具体可以参考官方文档:
Hook

  • 在 GORM 中保存、删除操作会默认运行在事务上, 因此在事务完成之前该事务中所作的更改是不可见的,如果Hook返回了任何错误,则修改将被回滚。

高级查询

初始化相关表

package main

import (
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"log"
	"os"
	"time"
)

type Employee struct {
	ID    uint    `gorm:"size:3"`
	Name  string  `gorm:"size:8"`
	Age   int     `gorm:"size:3"`
	Sex   bool    `gorm:"size:3"`
	Email *string `gorm:"size:32"`
}

var myDB *gorm.DB

func init() {
	//连接数据库
	user := "root"
	password := "ba161754"
	dbname := "gorm"
	ip := "127.0.0.1"
	port := "3306"
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", user, password, ip, port, dbname)
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		fmt.Println("数据库连接失败,err:", err)
		return
	}
	fmt.Println("数据库连接成功")
	myDB = db

	//初始化日志
	var mysqlLogger logger.Interface
	mysqlLogger = logger.Default.LogMode(logger.Info) //设置日志打印级别
	mysqlLogger = logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // (日志输出的目标,前缀和日志包含的内容)
		logger.Config{
			SlowThreshold:             time.Second, // 慢 SQL 阈值
			LogLevel:                  logger.Info, // 日志级别
			IgnoreRecordNotFoundError: true,        // 忽略ErrRecordNotFound(记录未找到)错误
			Colorful:                  true,        // 使用彩色打印
		},
	)
	myDB.Logger = mysqlLogger

	//创建所要使用的单表
	err = myDB.AutoMigrate(&Employee{})
	if err != nil {
		fmt.Println("创建表失败,err:", err)
		return
	}

	//插入测试数据
	employeeList := []Employee{
		{ID: 1, Name: "李元芳", Age: 32, Email: PtrString("lyf@yf.com"), Sex: true},
		{ID: 2, Name: "张武", Age: 18, Email: PtrString("zhangwu@lly.cn"), Sex: true},
		{ID: 3, Name: "枫枫", Age: 23, Email: PtrString("ff@yahoo.com"), Sex: true},
		{ID: 4, Name: "刘大", Age: 54, Email: PtrString("liuda@qq.com"), Sex: true},
		{ID: 5, Name: "李武", Age: 23, Email: PtrString("liwu@lly.cn"), Sex: true},
		{ID: 6, Name: "李琦", Age: 14, Email: PtrString("liqi@lly.cn"), Sex: false},
		{ID: 7, Name: "晓梅", Age: 25, Email: PtrString("xiaomeo@sl.com"), Sex: false},
		{ID: 8, Name: "如燕", Age: 26, Email: PtrString("ruyan@yf.com"), Sex: false},
		{ID: 9, Name: "魔灵", Age: 21, Email: PtrString("moling@sl.com"), Sex: true},
	}
	myDB.Create(&employeeList)
}

func PtrString(email string) *string {
	return &email
}

func main() {

}

Where查询

  • 简单示例:
	var employee Employee

	//Where
	myDB.Where("name like ?", "李%").Find(&employee) //查询姓李的
	fmt.Println(employee)
  • Not条件
	myDB.Not("name like ?", "李%").Find(&employee) //查询第一条不是姓李的
	fmt.Println(employee)
  • Or条件
	var employeeList []Employee
	myDB.Not("name like ?", "李%").Or("age>20").Find(&employeeList)  //用Where表示and
	for _, value := range employeeList {
		data, _ := json.Marshal(value)
		fmt.Println(string(data))
	}
  • And条件
	employeeList=[]Employee{}
	myDB.Not("name like ?", "李%").Where("age>20").Find(&employeeList)  //用Where表示and
	for _, value := range employeeList {
		data, _ := json.Marshal(value)
		fmt.Println(string(data))
	}

select选择字段

  • 简单示例
	employeeList := []Employee{}
	myDB.Select("name", "age").Find(&employeeList)
	for _, value := range employeeList {
		data, _ := json.Marshal(value)
		fmt.Println(string(data))
	}

  • Scan函数
    我们可以用Scan函数将搜索结果导入带新的结构体中
type Employee1 struct {
	Name string
	Age  int
}

	//select
	employeeList := []Employee{}
	employeeList1 := []Employee1{}
	myDB.Select("name", "age").Find(&employeeList).Scan(&employeeList1)
	for _, value := range employeeList1 {
		data, _ := json.Marshal(value)
		fmt.Println(string(data))
	}

输出为:
在这里插入图片描述

排序

	//排序
	employeeList := []Employee{}
	myDB.Order("age desc").Find(&employeeList)
	for _, value := range employeeList {
		data, _ := json.Marshal(value)
		fmt.Println(string(data))
	}

分页查询

	//分页
	employeeList := []Employee{}
	myDB.Limit(4).Offset(0).Order("age desc").Find(&employeeList) //Limit:每页限定记录数,offset:偏移量
	for _, value := range employeeList {
		data, _ := json.Marshal(value)
		fmt.Println(string(data))
	}

去重

	//去重
	var agelist []int
	myDB.Table("employees").Select("distinct age").Find(&agelist)
	for _, value := range agelist {
		fmt.Println(value)
	}

分组查询

	//分组查询
	var ageList []int
	// 查询男生的个数和女生的个数
	myDB.Table("employees").Select("count(id)").Group("Sex").Scan(&ageList)
	fmt.Println(ageList)

执行原生sql

	//执行原生sql
	type SexGroup struct {
		Count int `gorm:"column:count(id)"`
		Sex   bool
		Name  string `gorm:"column:group_concat(name)"`
	}
	var sexlist []SexGroup
	myDB.Raw("select count(id) ,sex,group_concat(name) from employees group by sex").Scan(&sexlist)
	for _, value := range sexlist {
		data, _ := json.Marshal(value)
		fmt.Println(string(data))
	}
}

子查询

	//子查询
	//select * from students where age > (select avg(age) from students); 原生sql
	myDB.Where("age > (?)", myDB.Model(&Employee{}).Select("avg(age)")).Find(&employee)
	fmt.Println(employee)

查询调用

我们可以在model层写一些通用的查询方法,让外界直接来调用:

func Age23(db *gorm.DB) *gorm.DB {
	return db.Where("age>?", 23)
}

	myDB.Scopes(Age23).Find(&employee)
	fmt.Println(employee)

完整代码

package main

import (
	"encoding/json"
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"log"
	"os"
	"time"
)

type Employee struct {
	ID    uint    `gorm:"size:3"`
	Name  string  `gorm:"size:8"`
	Age   int     `gorm:"size:3"`
	Sex   bool    `gorm:"size:3"`
	Email *string `gorm:"size:32"`
}

type Employee1 struct {
	Name string
	Age  int
}

var myDB *gorm.DB

func init() {
	//连接数据库
	user := "root"
	password := "ba161754"
	dbname := "gorm"
	ip := "127.0.0.1"
	port := "3306"
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", user, password, ip, port, dbname)
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		fmt.Println("数据库连接失败,err:", err)
		return
	}
	fmt.Println("数据库连接成功")
	myDB = db

	//初始化日志
	var mysqlLogger logger.Interface
	mysqlLogger = logger.Default.LogMode(logger.Info) //设置日志打印级别
	mysqlLogger = logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // (日志输出的目标,前缀和日志包含的内容)
		logger.Config{
			SlowThreshold:             time.Second, // 慢 SQL 阈值
			LogLevel:                  logger.Info, // 日志级别
			IgnoreRecordNotFoundError: true,        // 忽略ErrRecordNotFound(记录未找到)错误
			Colorful:                  true,        // 使用彩色打印
		},
	)
	myDB.Logger = mysqlLogger

	//创建所要使用的单表
	err = myDB.AutoMigrate(&Employee{})
	if err != nil {
		fmt.Println("创建表失败,err:", err)
		return
	}

	//插入测试数据
	employeeList := []Employee{
		{ID: 1, Name: "李元芳", Age: 32, Email: PtrString("lyf@yf.com"), Sex: true},
		{ID: 2, Name: "张武", Age: 18, Email: PtrString("zhangwu@lly.cn"), Sex: true},
		{ID: 3, Name: "枫枫", Age: 23, Email: PtrString("ff@yahoo.com"), Sex: true},
		{ID: 4, Name: "刘大", Age: 54, Email: PtrString("liuda@qq.com"), Sex: true},
		{ID: 5, Name: "李武", Age: 23, Email: PtrString("liwu@lly.cn"), Sex: true},
		{ID: 6, Name: "李琦", Age: 14, Email: PtrString("liqi@lly.cn"), Sex: false},
		{ID: 7, Name: "晓梅", Age: 25, Email: PtrString("xiaomeo@sl.com"), Sex: false},
		{ID: 8, Name: "如燕", Age: 26, Email: PtrString("ruyan@yf.com"), Sex: false},
		{ID: 9, Name: "魔灵", Age: 21, Email: PtrString("moling@sl.com"), Sex: true},
	}
	myDB.Create(&employeeList)
}

func PtrString(email string) *string {
	return &email
}

func Age23(db *gorm.DB) *gorm.DB {
	return db.Where("age>?", 23)
}

func main() {
	employee := Employee{}
	employeeList:=[]Employee{}

	//Where
	myDB.Where("name like ?", "李%").Find(&employee) //查询姓李的
	fmt.Println(employee)
	
	myDB.Not("name like ?", "李%").Find(&employee) //查询第一条不是姓李的
	fmt.Println(employee)
	
	myDB.Not("name like ?", "李%").Or("age>20").Find(&employeeList) //用Where表示and
	for _, value := range employeeList {
		data, _ := json.Marshal(value)
		fmt.Println(string(data))
	}
	
	employeeList = []Employee{}
	myDB.Not("name like ?", "李%").Where("age>20").Find(&employeeList) //用Where表示and
	for _, value := range employeeList {
		data, _ := json.Marshal(value)
		fmt.Println(string(data))
	}

	//select
	employeeList = []Employee{}
	employeeList1 := []Employee1{}
	myDB.Select("name", "age").Find(&employeeList).Scan(&employeeList1)
	for _, value := range employeeList1 {
		data, _ := json.Marshal(value)
		fmt.Println(string(data))
	}

	//排序
	employeeList = []Employee{}
	myDB.Order("age desc").Find(&employeeList)
	for _, value := range employeeList {
		data, _ := json.Marshal(value)
		fmt.Println(string(data))
	}

	//分页
	employeeList = []Employee{}
	myDB.Limit(4).Offset(0).Order("age desc").Find(&employeeList) //Limit:每页限定记录数,offset:偏移量
	for _, value := range employeeList {
		data, _ := json.Marshal(value)
		fmt.Println(string(data))
	}

	//去重
	var agelist []int
	myDB.Table("employees").Select("distinct age").Find(&agelist)
	for _, value := range agelist {
		fmt.Println(value)
	}

	//分组查询
	var ageList []int
	// 查询男生的个数和女生的个数
	myDB.Table("employees").Select("count(id)").Group("Sex").Scan(&ageList)
	fmt.Println(ageList)

	//执行原生sql
	type SexGroup struct {
		Count int `gorm:"column:count(id)"`
		Sex   bool
		Name  string `gorm:"column:group_concat(name)"`
	}
	var sexlist []SexGroup
	myDB.Raw("select count(id) ,sex,group_concat(name) from employees group by sex").Scan(&sexlist)
	for _, value := range sexlist {
		data, _ := json.Marshal(value)
		fmt.Println(string(data))
	}

	//子查询
	//select * from students where age > (select avg(age) from students); 原生sql
	myDB.Where("age > (?)", myDB.Model(&Employee{}).Select("avg(age)")).Find(&employee)
	fmt.Println(employee)

	//查询引用Scope
	myDB.Scopes(Age23).Find(&employee)
	fmt.Println(employee)
}

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

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

相关文章

C++习题(1)

一、题目描述&#xff1a; 二、代码展示&#xff1a; #include <iostream> #include <iomanip> using namespace std; struct Student{char name[20];int id;int age;float score; }; int main() {int n;cin>>n;Student student[n];float sum0.0;for(int i0…

小易大数据:大数据报告查询领域的黑马,这些优势让你无法忽视!

随着大数据技术被运用到各行各业&#xff0c;风控领域也不例外&#xff0c;形成了基于大数据技术的大数据信用&#xff0c;也就是我们常说的大数据报告或者网贷大数据&#xff0c;在众多的查询平台中&#xff0c;小易大数据平台在市面上是比较受欢迎的&#xff0c;那在小易平台…

JAVASE2

封装的步骤&#xff1a; 1、所有属性私有化&#xff0c;使用private关键字进行修饰&#xff0c;private表示私有的&#xff0c;修饰的所有数据只能在本类中访问 2、对外提供简单入口&#xff1a;比如说被private修饰的成员变量&#xff0c;在其他类中只能通过getXxx/setXxx方法…

Linux之多进程

c程序获取进程pid和ppid 在 Linux 系统中管理进程使用树型管理方式每个进程都需要与其他某一个进程建立 父子关系, 对应的进程则叫做 父进程 Linux 系统会为每个进程分配 id , 这个 id 作为当前进程的唯一标识, 当进程结束, 则会回收 进程的 id 与 父进程的 id 分别通过 getpi…

马斯克:AI时代人人高收入,不需要工作,商品服务不再短缺,可能性80%

当前人工智能现状和未来如何&#xff1f;AI时代下&#xff0c;人类未来会发生哪些变化&#xff1f; 埃隆马斯克&#xff08;Elon Musk&#xff09;在2024 VivaTech大会上分享了关于地球未来的诸多愿景。 投资作业本课代表摘录了其中的要点&#xff0c;分享给大家&#xff1a…

c语言基础:数组的运用以及在内存中的地址的理解

目录 目录&#xff1a; 1.数组作为函数参数 2.数组在内存中的存储 2.1数组名是什么&#xff1f; 2.2下面我们来探讨二维数组的各个名字表示什么 二维数组的首元素地址是什么呢&#xff1f; *arr表示的是什么呢 &#xff1f;&#xff08;arr是二维数组&#xff09; 1.数组作…

C语言 | Leetcode C语言题解之第116题填充每个节点的下一个右侧节点指针

题目&#xff1a; 题解&#xff1a; struct Node* connect(struct Node* root) {if (root NULL) {return root;}// 从根节点开始struct Node* leftmost root;while (leftmost->left ! NULL) {// 遍历这一层节点组织成的链表&#xff0c;为下一层的节点更新 next 指针stru…

echarts学习篇

一、使用echarts 1.引入 Apache ECharts <!DOCTYPE html> <html> <head> <meta charset"utf-8" /> <!-- 引入刚刚下载的 ECharts 文件 --> <script src"echarts.js"></script> </head> </html> 2.…

设计模式 19 模板模式 Template Pattern

设计模式 19 模板模式 Template Pattern 1.定义 模板模式&#xff08;Template Pattern&#xff09;是一种行为设计模式&#xff0c;它定义了一个算法的骨架&#xff0c;将一些步骤的具体实现延迟到子类中。在模板模式中&#xff0c;定义了一个抽象类&#xff0c;其中包含了一个…

[论文笔记]Chain-of-Thought Prompting Elicits Reasoning in Large Language Models

引言 今天带来思维链论文 Chain-of-Thought Prompting Elicits Reasoning in Large Language Models的笔记。 作者探索了如何通过生成一系列中间推理步骤的思维链&#xff0c;显著提升大型语言模型在进行复杂推理时的能力。 1 总体介绍 语言模型的规模扩大已被证明能够带来…

基于Netty实现安全认证的WebSocket(wss)服务端

1.Netty服务端 服务端代码参考【基于Netty实现WebSocket服务端-CSDN博客】中的两种方式都可以&#xff1b;这里用的是第一种简单方式。 新增如下逻辑&#xff1a;添加SSLHandler SSLContext sslContext SslUtil.createSSLContext("JKS","D:\\workSpace\\day…

编译qt5.15.2(mac/windows)的mysql驱动(附带编译好的文件)

文章目录 0 背景1 编译过程2 福利 0 背景 因为需要连接到mysql数据库&#xff0c;所以需要连mysql驱动。 1 编译过程 1&#xff0c;打开文件/Users/mac/Qt5.14.2/5.14.2/Src/qtbase/src/plugins/sqldrivers/sqldrivers.pro&#xff0c;注释掉QMAKE_USE mysql&#xff1b; 如…

[数智人文实战] 02.舆情分析之词云可视化、文本聚类和LDA主题模型文本挖掘

【数智人文与文本挖掘】知识星球建立且正式运营,欢迎新老博友和朋友加入,一起分享更多数智人文知识和交流进步。该星球计划每周至少分享7个资源或文章,包括数智人文、文本挖掘、人工智能、大数据分析和图书情报的技术文章、代码及资源。同时,欢迎进入星球的朋友咨询我图情和…

多线程基本常识

多线程的状态 在Java中&#xff0c;一个线程的生命周期有以下几种状态&#xff1a; 新建&#xff08;New&#xff09;&#xff1a;当线程对象被创建时&#xff0c;线程处于新建状态。此时线程对象存在&#xff0c;但还没有调用start()方法启动线程。 运行&#xff08;Runnable…

Vulnhub - AI-WEB-1.0靶机教程

目录 站点信息收集 c段扫描 端口扫描 目录扫描 漏洞利用 使用 burp 抓包 查询数据库名 查询数据库下的表 查询表中的字段名 查询字段中的数据 --os-shell 上传一句话木马 下载地址&#xff1a;https://download.vulnhub.com/aiweb/AI-Web-1.0.7z 我们从站点信息收…

【C/C++】观察者模式

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

LAMP网络服务架构

目录 LAMP 网站服务架构 LAMP的组成部分 LAMP的构建顺序 安装论坛 0.电脑已编译安装Apache&#xff0c;MySQL&#xff0c;PHP 1.创建数据库&#xff0c;并进行授权 2.上传论坛压缩包到 /opt ,并解压 3.上传站点更新包 4.更改论坛目录的属主 5.浏览器访问验证 LAMP 网…

授权调用: 介绍 Transformers 智能体 2.0

简要概述 我们推出了 Transformers 智能体 2.0&#xff01; ⇒ &#x1f381; 在现有智能体类型的基础上&#xff0c;我们新增了两种能够 根据历史观察解决复杂任务的智能体。 ⇒ &#x1f4a1; 我们致力于让代码 清晰、模块化&#xff0c;并确保最终提示和工具等通用属性透明化…

PPT大珩助手新功能-生成迷宫

大珩助手是一款功能丰富的办公软件插件&#xff0c;它主要分为两个版本&#xff1a;PPT大珩助手和Word大珩助手。这两个版本都旨在提高用户在处理演示文稿和文档时的效率。 PPT大珩助手 这是一款专门为Microsoft PowerPoint设计的插件。它提供了多种功能&#xff0c;例如素材…

深入理解Kubernetes的调度核心思想

一、引言 Kubernetes&#xff08;简称K8s&#xff09;是一个开源的容器编排系统&#xff0c;用于自动化部署、扩展和管理容器化应用程序。在Kubernetes集群中&#xff0c;调度器是一个核心组件&#xff0c;它负责将Pod&#xff08;Kubernetes中的最小部署单元&#xff09;分配…