Gorm连接以及CURD实战+测试

news2024/11/15 11:12:14

Gorm CRUD

前言

Gormgo的一个ORM框架,官方文档地址为-> GORM 指南

本文将介绍与gorm有关的CRUD操作,操作数据库类型为mysql数据库

数据库连接

func Open(dialector Dialector, opts …Option) (db *DB, err error)

该函数用于进行gorm连接对应数据库

输入 go get -u "gorm.io/gorm" 下载gorm库
输入 go get -u gorm.io/driver/mysql 即可下载mysql驱动

对于mysql的连接,还需要引入gorm的mysql驱动,否则没有Open这个函数

var gormDb *gorm.DB

func initGormDB() {
	var err error
	gormDb, err = gorm.Open(
		mysql.Open("root:xxxxxx@tcp(127.0.0.1:3306)/go_db?charset=utf8mb4&parseTime=True&loc=Local"),
		&gorm.Config{
			PrepareStmt:            true, //缓存预编译命令
			SkipDefaultTransaction: true, //禁用默认事务操作
		},
	)
	if err != nil {
		// 这里因为是panic所以可以直接进行赋值操作,如果不是panic需要在错误之后才能进行赋值给全局变量
		panic(err)
	}
	fmt.Println("gormDb connection success~")
}

下图将给出gormConfig的配置

在这里插入图片描述

支持自定义logger,但是需要实现对应接口的方法

// Interface logger interface
type Interface interface {
   LogMode(LogLevel) Interface
   Info(context.Context, string, ...interface{})
   Warn(context.Context, string, ...interface{})
   Error(context.Context, string, ...interface{})
   Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error)
}

因为gorm底层是通过使用 database/sql 维护连接池

因此可以获取sqlDB,然后设置连接池

sqlDB, err := gormDb.DB()

// SetMaxIdleConns 设置空闲连接池中连接的最大数量
sqlDB.SetMaxIdleConns(10)

// SetMaxOpenConns 设置打开数据库连接的最大数量。
sqlDB.SetMaxOpenConns(100)

// SetConnMaxLifetime 设置了连接可复用的最大时间。
sqlDB.SetConnMaxLifetime(time.Hour)

数据库迁移

下图是gorm中关于数据库迁移的源代码,给出了自动迁移和手动迁移两种方案,而自动迁移其实和手动迁移没有区别。

// Migrator returns migrator
func (db *DB) Migrator() Migrator {
   tx := db.getInstance()

   // apply scopes to migrator
   for len(tx.Statement.scopes) > 0 {
      scopes := tx.Statement.scopes
      tx.Statement.scopes = nil
      for _, scope := range scopes {
         tx = scope(tx)
      }
   }

   return tx.Dialector.Migrator(tx.Session(&Session{}))
}

// AutoMigrate run auto migration for given models
func (db *DB) AutoMigrate(dst ...interface{}) error {
   return db.Migrator().AutoMigrate(dst...)
}

迁移数据库

结构体中要嵌套gorm的Model结构体,用于管理软删除和时间

type Model struct {
   ID        uint `gorm:"primarykey"`
   CreatedAt time.Time
   UpdatedAt time.Time
   DeletedAt DeletedAt `gorm:"index"`
}
type GormUser struct {
   gorm.Model
	Age      int    `gorm:"age"`
	Name     string `gorm:"name"`
	Password string `gorm:"password"`
}

// Migrant 数据库迁移
func Migrant() error {
   return gormDb.AutoMigrate(&GormUser{})
}

在tag处可以选择gorm中的字段名,我这里只做演示操作,数据与实际开发并不相符

测试

使用 go test -run=Migrant -v 该命令可以详细打印出测试结果

func TestMain(m *testing.M) {
   initGormDB()
   code := m.Run()
   os.Exit(code)
}

func TestMigrant(t *testing.T) {
   err := Migrant()
   if err != nil {
      t.Errorf("Migrant fail,%v", err)
   }
}

在这里插入图片描述

CRUD实战

创建

func (db *DB) Create(value interface{}) (tx *DB)

增加一条用户信息

// GormCreate gorm 创建数据
func GormCreate() error {
   u := GormUser{
      Name:     "张三",
      Age:      15,
      Password: "qwer",
   }
   return gormDb.Create(&u).Error
}

在这里插入图片描述

测试

go test -run=GormCreate -v

func TestGormCreate(t *testing.T) {
   err := GormCreate()
   if err != nil {
      t.Errorf("Migrant fail,%v", err)
   }
}

在这里插入图片描述

增加多条用户信息

通过切片或者数组的方式插入多条数据

// GormCreateMore gorm 创建多条数据
func GormCreateMore() error {
   u := GormUser{
      Name:     "张三",
      Age:      15,
      Password: "qwer",
   }
   u2 := GormUser{
      Name:     "李四",
      Age:      16,
      Password: "qwer",
   }
   u3 := GormUser{
      Name:     "王五",
      Age:      17,
      Password: "qwer",
   }
   uu := [...]GormUser{u, u2, u3}
   return gormDb.Create(&uu).Error
}

测试

func TestGormCreateMore(t *testing.T) {
   err := GormCreateMore()
   if err != nil {
      t.Errorf("Migrant fail,%v", err)
   }
}

在这里插入图片描述

删除

func (db *DB) Delete(value interface{}, conds …interface{}) (tx *DB)

gorm中有两种删除方法

  • 硬删除,直接通过结构体中的字段值进行删除
  • 条件删除,先进行where查询然后删除
// GormDelete gorm 删除数据
func GormDelete() error {
   // 直接删除
   gormDb.Delete(&GormUser{Name: "张三"})
   // 条件删除 
   return gormDb.Where("name = ?", "张三").Delete(&GormUser{}).Error
}

测试

这里出错是因为我删除了两次

func TestGormDelete(t *testing.T) {
   err := GormDelete()
   if err != nil {
      t.Errorf("Migrant fail,%v", err)
   }
}

在这里插入图片描述

gorm中删除使用的是软删除,好处是不会产生碎片化数据,方便维护。
在这里插入图片描述

修改

修改的方法起码有四种,两种批量修改,两种单行修改。还可以进行保存

在这里插入图片描述

保存修改

u := GormUser{}
//先查询一条记录, 保存在模型变量u
//等价于: SELECT * FROM `gorm_users`  WHERE (id = '2') LIMIT 1
db.Where("id = ?", 3).Take(&u)
u.age = 100
db.Save(&u)

直接修改

Model用于绑定操作的数据库

gormDb.Model(&GormUser{}).Update("age", 25).Where("id", 3).Error

在这里插入图片描述

显然该操作不行,报错说该操作没有where,因此可以得出where语句必须要在Update之前。所以我们可以再尝试一次

gormDb.Model(&GormUser{}).Where("id", 3).Update("age", 25).Error

在这里插入图片描述

测试成功

查询

func (db *DB) First(dest interface{}, conds …interface{}) (tx *DB)
First finds the first record ordered by primary key, matching given conditions conds

First 用来查询单条数据,对所有数据进行正序排序并且放回第一条

等价于:SELECT * FROM gorm_users ORDER BY gorm_users.id ASC LIMIT 1

// GormQuery gorm 查询数据
func GormQuery(u *GormUser) error {
   return gormDb.First(u).Error
    // gormDb.Last(u).Error Last与First刚好相反(逆序排列),就不再测试了
}

测试

func TestGormQuery(t *testing.T) {
   u := GormUser{}
   err := GormQuery(&u)
   if err != nil {
      t.Errorf("gormQuery fail,%v", err)
   }
   t.Logf("gormUser first, data: %v", u)
}

在这里插入图片描述

func (db *DB) Take(dest interface{}, conds …interface{}) (tx *DB)
Take finds the first record returned by the database in no specified order, matching given conditions conds

Take 查询单条

等价于:SELECT * FROM gorm_users LIMIT 1

指定查询单条数据并返回查询行数

// GormQuery gorm 查询数据
func GormQuery(u *GormUser) (cnt int64, err error) {
   err = gormDb.Where("age = ?", 18).Count(&cnt).First(u).Error
   return
}

在这里插入图片描述

查询失败的原因是需要Model,或者Table,提前指定表名。因此我们加上之后可以再次尝试

// GormQuery gorm 查询数据
func GormQuery(u *GormUser) (cnt int64, err error) {
   err = gormDb.Model(&GormUser{}).Where("age = ?", 18).Count(&cnt).First(u).Error
   return
}

测试

func TestGormQuery(t *testing.T) {
   u := GormUser{}
   rowNum, err := GormQuery(&u)
   if err != nil {
      t.Errorf("gormQuery fail,%v", err)
   }
   t.Logf("gormUser first, data: %v\n", u)
   t.Logf("gormQuery method queryRows = %d", rowNum)
}

在这里插入图片描述

查到了三条数据,但我用的First,因此只返回一条数据。

查询多条数据

func (db *DB) Find(dest interface{}, conds …interface{}) (tx *DB)

Find finds all records matching given conditions conds

Find 用于查询多条数据

// GormQueryMore gorm 查询多条数据
func GormQueryMore(u []*GormUser) (cnt int64, err error) {
   err = gormDb.Model(&GormUser{}).Where("age = ?", 18).Count(&cnt).Find(u).Error
   return
}

测试

func TestGormQueryMore(t *testing.T) {
   u := make([]*GormUser, 3)
   rowNum, err := GormQueryMore(u)
   if err != nil {
      t.Errorf("gormQuery fail,%v", err)
   }
   for i, v := range u {
      t.Logf("gormUser first,第%d条数据, data: %v\n", i, v)
   }
   t.Logf("gormQuery method queryRows = %d", rowNum)
}

在这里插入图片描述

小结

gorm底层仍然是database/sql,因此原生的sql方法仍然能够被使用。对于gorm的CRUD简单操作就介绍到这里了。如果感兴趣的话可以到gorm的官网更深入的研究。

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

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

相关文章

中国市场手机出货量跌穿3亿部,苹果也顶不住了,只有三星暗爽

多家市调机构都给出了2022年中国智能手机市场的数据,数据虽然有些出入,不过都认为中国市场的手机出货量跌穿了3亿部,创下近10年来的新低纪录,国产手机尤其惨,而曾逆势增长的苹果也开始出现下滑。市调机构IDC给出的数据…

词法分析器Flex学习1 - Flex识别关键字

以前曾写过2篇Flex和Bison入门应用的文章; https://blog.csdn.net/bcbobo21cn/article/details/112343850 https://blog.csdn.net/bcbobo21cn/article/details/106193648 我只记得Flex是词法分析器,Bison是语法分析器; 只是一些入门的介绍&…

基于SSM+Layui的图书管理系统(Java版 附源代码及数据库)

目录 功能要求 技术栈 项目架构 登录界面 系统首页 借阅管理 图书管理 读者管理 类型管理 公告管理 管理员管理 统计分析 数据库设计 源代码数据库资料 毕设项目专栏 功能要求 (1)对系统登陆后进行增删改查功能 (2)…

文档管理对人力资源部门的重要影响

文档管理对人力资源部门的重要影响 当人力资源的管理功能是基于纸张或依赖于 Excel 电子表格、共享驱动器和其他无法与其他系统共享数据的软件等技术时,人力资源管理既耗时又耗费劳动力。用数字工作流程取代纸质流程可以简化从招聘和入职到绩效评估的流程。 随着组…

Elasticsearch(七)--ES文档的操作(下)---删除文档

一、前言 上篇文章我们了解了ES的修改文档的操作,也同样分别通过ES的kibana客户端以及Java高级Rest客户端进行学习,那么本篇末尾要给大家介绍的是对文档的删除操作,同新修改文档,也有删除单条文档和批量删除文档操作,…

工赋开发者社区 | 工业5.0为何是下一个10年的制造业关键性变革方向?

近年来,全球经济发展面临下行压力,世界各国重新认识到制造业在拉动经济增长、创造就业机会等方面的作用。欧洲在这种压力下提出了全新的工业5.0发展概念,试图重振制造业并再次引领全球工业发展潮流。本文小编分享一篇来自KNOWHOW的文章&#…

【地铁上的Redis与C#】数据类型(八)--set类型基本操作

这篇文章,我们开始学习set类型,学习set类型前我们先来看一下List类型有什么缺点。 List的缺点 当需要存储大量数据并且要提供高效率的查询时,List是无法完全实现的,这是因为list的存储结构是链表的形式,链表读取数据…

Leetcode力扣秋招刷题路-0114

从0开始的秋招刷题路,记录下所刷每道题的题解,帮助自己回顾总结 114. 二叉树展开为链表(Mid) 给你二叉树的根结点 root ,请你将它展开为一个单链表: 展开后的单链表应该同样使用 TreeNode ,其中…

Linux- 系统随你玩之--文本、字符串处理摸金校尉--RE

文章目录1、前言2、正则表达式2.1、 概述2.2、 特点2.3、正则表达式-测试工具3、知识点3.1、 正则表达式定义3.2、 正则表达式的组成3.3、正则表达式语法支持情况4、速记理解技巧4.1、基础正则表达式4.2、等价4.3、常用运算符与表达式4.4、分割语法4.4.1、例型4.4.2、例型语法与…

Java高手速成 | JSP MVC模式项目案例

MVC模式的核心思想是有效地组合“视图”“模型”和“控制器”。在JSP 技术中,视图是一个或多个JSP页面,其作用主要是向控制器提交必要的数据和为模型提供数据显示;模型是一个或多个Javabean对象,用于存储数据;控制器是…

LifeCycle源码解析

简介 Lifecycle是Jetpack中的一个生命周期组件,可用来感知其他组件(如Activity,Fragment)生命周期的变化,从而可以保证我们的一些代码操作控制在合理的生命周期内; 如何使用? 添加以下依赖 …

什么是接口、接口测试、接口自动化测试、你分的清楚吗?

目录 前言: 服务端接口测试介绍 什么是服务端? 什么是接口? 什么是接口测试? 为什么要做接口测试? 如何做接口测试? 接口测试自动化介绍 为什么是接口测试自动化? 为什么要做接口测试自…

什么是动态域名解析?域名怎么解析到内网IP

首先说说什么是域名解析,域名解析就是把域名解析成一个ip地址,我们大多数人都喜欢记忆域名,但是机器只认识IP地址,把这个IP地址对应相关域名,这就叫域名解析。动态域名与动态域名解析是相互关联的关系,通过…

项目图床选择

总结: 非隐私图片:使用Github、七牛云(http)、SM.MS图床、路过图床。隐私图片:使用阿里云OSS、七牛云(https)(绑定的域名不能丢)。 测试环境(日常使用)自行选择; 生产环境选择阿里云…

03_PyTorch 模型训练[Dataset 类读取数据集]

PyTorch 读取图片,主要是通过 Dataset 类,所以先简单了解一下 Dataset 类。Dataset 类作为所有的 datasets 的基类存在,所有的 datasets 都需要继承它,类似于 C中的虚基 类。这里重点看 getitem 函数,getitem 接收一个…

微信小程序使用canvas生成分享海报功能复盘

前言 近期需要开发一个微信小程序生成海报分享的功能。在h5一般都会直接采用 html2canvas 或者 dom2image 之类的库直接处理。但是由于小程序不具备传统意义的dom元素,所以也没有办法采用此类工具。 所以就只能一笔一笔的用 canvas 画出来了,下面对实现…

(文末有彩蛋,不看白不看)兑现一下之前答应读者的事

大家过年好呀!(我)明天就要开工上班啦!在假期的最后一天踢了会球,简单吃点东西,晚上来兑现答应一位读者的事情。开整! 前情提要 这篇文章缘起于「开发者」技术交流群中一位读者遇到的问题&…

《树上的男爵》坚持解释不清的理想是疏离,还是自由?

《树上的男爵》坚持解释不清的理想是疏离,还是自由? 伊塔洛卡尔维诺,意大利作家,后现代主义派。 卡尔维诺为“寓言式奇幻文学的大师”。(评论家赫伯特密特甘评) 吴正仪 译 许多年来,我为一些连我…

【3】SpringBoot基础

//从事微服务开发工作 SpringBoot提供一种快速使用Spring的方式 1、自动化 2、设置多个starter配置依赖比Maven直接管理更便捷 3、内置服务器 总结:自动配置,起步依赖,辅助功能 2.6.11版本的说明书 Spring Boot Reference Documentation…

第九层(8):STL之set/multiset

文章目录前情回顾set/multiset概念区别构造函数赋值函数大小操作函数交换函数插入函数删除函数查找函数统计函数为什么set不可以插入重复数据pair数组pair数组创建怎么样去改变set容器的排序规则下一座石碑🎉welcome🎉 ✒️博主介绍:一名大一…