gorm重要知识点讲解大全

gorm

本人这段时间在学习go语言,以下是学习过程中写的gorm笔记,一方面是自己学习的总结,一方面也想与大家分享观点。

基础操作

结构体标签

常用方法

最基础操作

连接,建表,删表,判断是否存在等等

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql" //引入mysql驱动
)
// 定义结构体
type User struct {
    Age  int
    Name string
}
func main() {
    //连接数据库:
    //Open传入两个参数:
    //第一个参数:指定你要连接的数据库
    //第二个参数:指的是数据库的设置信息:
    //用户名:密码@tcp(ip:port)/数据库名字?charset=utf8&parseTime=True&loc=Local
    //charset=utf8设置字符集
    //parseTime=True是为了处理time.Time
    //loc=Local时区设置
    db, err := gorm.Open("mysql", "root:1234@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
    if err != nil {
       panic(err)
    }
    defer db.Close()

    //创建表:通常情况下数据库中新建的名字是结构体名字的复数形式,例如结构体User。表users
    //db.CreateTable(&User{})
    //db.Table("user").CreateTable(&User{})
    db.DropTable(&User{}) //通过&User{}删除users表
    db.DropTable("user")  //通过“user”删除user表

    //判断表是否存在
    flag1 := db.HasTable(&User{})
    fmt.Println(flag1)
    flag2 := db.HasTable("user")
    fmt.Println(flag2)
}
进行增删改操作
增加
//增加
//db.Create(&User{Age: 18, Name: "丽丽"}) //

相关函数:

//db.First()是GORM(Go语言的ORM库)中的一个函数,用于从数据库中 查询并返回第一条记录。
//它的作用是根据指定的条件,按照默认的排序规则从数据库中查询匹配的第一条记录。
db.First(&result, "condition")
其中,`&result`表示查询结果将会存储在`result`变量中,`"condition"`表示查询条件。
查询
//查询:需要查询出来数据的载体,即查询的数据需要有东西存放
var myuser User   //定义myuser来存放数据
db.First(&myuser, "age= ?", 18)
fmt.Println(myuser)
修改或更新数据:

前提是你已经有载体把原来的数据放起来了

意思是说:需要更新数据就得先查询,在更新

db.Model(&myuser).Update("age", 30)
db.Model(&myuser).Update("name", "绯绯")
删除数据:
        //删除数据:
        //需要做的:先查询,再删除
        db.Delete(&myuser)

模型名和表名映射

上文已经讲了数据库对象会以大写字母小写,尾部复数的形式出现在数据库中,下边是详细的映射规则

  1. (1)如果模型名没有驼峰命名,那么表名就是:模型名小写+复数形式: 如模型名User-》表名users
  2. (2)如果模型名有驼峰命名,那么表名就是:大写变小写并在前面加下划线,最后加复数形式:如模型名UserInfo-》表名user_infos
  3. (3)如有模型名有连续的大写字母,那么表名就是:连续的大写字母变小写,驼峰前加下划线,字母变小写,最后加复数形式:如模型名:DBUserInfo->>>表名db_user_infos

代码示例:

package main
import (
        "github.com/jinzhu/gorm"
        _ "github.com/jinzhu/gorm/dialects/mysql"
)
//定义结构体:
type User struct {
        Age int
        Name string
}
type UserInfo struct {
        Age int
        Name string
}
type DBUserInfo struct {
        Age int
        Name string
}
type MyUser struct {
        Age int
        Name string
}
func (MyUser) TableName() string{
        return "test_my_user"
}
func main(){
        //连接数据库:
        db,err := gorm.Open("mysql","root:root@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
        if err != nil {
                panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
        }
        //数据库资源释放:
        defer db.Close()
        //创建表:通常情况下,数据库中新建的标的名字是结构体名字的复数形式,例如结构体User,表名 users
        db.CreateTable(&User{})
        db.CreateTable(&UserInfo{})
        db.CreateTable(&DBUserInfo{})
        db.CreateTable(&MyUser{})
}

image-20231111154851742

gorm.Model匿名字段

目的是为了简化操作

只需要在自己的模型中指定gorm.Model匿名字段,即可在数据库表中包含四个字段:ID,CreatedAt,UpdatedAt,DeletedAt

自动生成四个能用上的字段

ID:主键自增长

CreatedAt:用于存储记录的创建时间

UpdatedAt:用于存储记录的修改时间

DeletedAt:用于存储记录的删除时间

示例:

// 定义结构体:
type User struct {
    gorm.Model //匿名字段
    Age        int
    Name       string
}

func main() {
    //连接数据库:
    db, err := gorm.Open("mysql", "root:1234@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
    if err != nil {
       panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
    }
    //数据库资源释放:
    defer db.Close()
    //创建表:通常情况下,数据库中新建的标的名字是结构体名字的复数形式,例如结构体User,表名 users
    db.CreateTable(&User{})
}

image-20231111155458900

结构体标签gorm:" "

就是用go来代替mysql的建表语句

先上示例:

type Student struct {
        StuID int `gorm:"primary_key;AUTO_INCREMENT"`
使用primary_key标签指定它为主键,AUTO_INCREMENT标签表示它是自增的。        
        Name string `gorm:"not null"`
        //这个字段用于表示学生的姓名,使用not null标签指定它不能为空。
        Age int `gorm:"unique_index"`
        //使用unique_index标签指定它是唯一索引,即每个年龄值只能出现一次。
        Email string `gorm:"unique"`
        //使用unique标签指定它必须是唯一的,即每个邮箱只能出现一次。
        Sex string `gorm:"column:gender;size:10"`
        //这个字段用于表示学生的性别,使用column标签指定它在数据库中的列名为gender即结构体中和数据库中名字不同,但表示同一数据,size标签指定它的长度为10
        Desc string `gorm:"-"`
        //用于表示学生的描述信息,使用了-标签,表示在数据库中不需要映射此字段,即只在代码中有,数据库没有
        Classno string `gorm:"type:int"`
        //这个字段用于表示学生的班级编号,使用type标签指定它的数据类型为int。
}

相信学过数据库的一眼就能认出很多,以下是全部标签

、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

通过结构体标签gorm来实现表的约束
【2】gorm标签属性值:
(1)-: 忽略,不映射这个字段 eg: gorm:"-" ,适合:一些冗余字段,不想在数据库中体现,只想在结构体中体现
(2)primary_key:主键 eg: gorm:"primary_key"
PS:如果是想要加联合主键,在每个字段后加入 gorm:"primary_key"即可
例如:即可将StuID和Name作为联合主键
StuID int gorm:"primary_key"
Name string gorm:"primary_key"
(3)AUTO_INCREMENT:自增 eg: gorm:"AUTO_INCREMENT"
(4)not null:不为空,默认为空 eg: gorm:"not null"
(5)index:索引, eg: gorm:"index"
创建索引并命名:eg: gorm:"index:idx_name_code"
(6)unique_index:唯一索引 eg: gorm:"unique_index"
唯一性索引unique index和一般索引normal index最大的差异就是在索引列上增加了一层唯一约束。添加唯一性索引的数据列可以为空,但是只要存在数据值,就必须是唯一的。
(7)unique:唯一 eg: gorm:"unique"
(8)column:指定列名 eg: gorm:"column:user_name"
(9)size:字符串长度,默认为255 eg:gorm:"size:10"
(10)default default:'男' 默认值
(11)type:设置sql类型 eg: gorm:"type:int(2)"
PS:多个属性值之间用分号分隔

表关系

示例:
结构体User,UserInfo:

package demostruct
type User struct{
        UserId int `gorm:"primary_key;AUTO_INCREMENT"`
        Age int
        Name string
}
type UserInfo struct {
        InfoID int `gorm:"primary_key;AUTO_INCREMENT"`
        Pic string
        Address string
        Email string
        //关联关系
        User User
        //指定外键
        UserId int
}

Association方式查询,先First查询,再Associaion查询,费劲

//db.Model(&userinfo).Association("User").Find(&userinfo.User)
//fmt.Println(userinfo)
//{1 /upload/1.jpg 北京海淀区 124234@126.com {1 19 丽丽 1}}

Proload方式查询:通常会用这个,更方便

db.Preload("User").Find(&userinfo, "info_id=?", 1)
fmt.Println(userinfo)
//{1 /upload/1.jpg 北京海淀区 124234@126.com {1 19 丽丽 1}}

Related

var user demostruct.User
//拖过userinfo模型查出来的User字段放到新的容器user中:
db.Model(&userinfo).Related(&user, "User")
fmt.Println(user)
fmt.Println(userinfo)
//{1 19 丽丽 1}
//{1 /upload/1.jpg 北京海淀区 124234@126.com {0 0  0}}
Ps:查出的数据是分开存放的

通过UserInfo表数据对User表中数据进行更新

// 创建表:通常情况下,数据库中新建的标的名字是结构体名字的复数形式,例如结构体User,表名 users
var userinfo demostruct.UserInfo
db.Preload("User").Find(&userinfo, "info_id=?", 1)

fmt.Println(userinfo)
//再更新:注意:Update的参数age可以用结构体中字段,也可以用数据库字段
db.Model(&userinfo.User).Update("age", 31)
fmt.Println(userinfo)

删除

db.Delete()

一对多多对多

gorm中常用方法(命令):

包含各种建表查询删除的常用方法

  • 【1】First:按照条件查询,并且升序排列,查询出一条记录
  • 【2】FirstOrCreate:有数据就查询出来,没有就创建一条记录
  • 【3】Last:按照条件查询,并且降序排列,查询出一条记录
  • 【4】Take:按照条件查询,查询出一条记录

2,3,4在通常结果是一样的,需要打印sql语句才能看出区别

  • 【5】Find:按照条件查询:可以同时查多个

下边是这五个方法的示例:

First
//db.Debug().First(&user, "user_id=?", 1)
// SELECT * FROM `users`  WHERE (user_id=1) ORDER BY `users`.`user_id` ASC LIMIT 1
//其实效果和
db.Debug().First(&user, 1) //是一样的:
//SELECT * FROM `users`  WHERE (`users`.`user_id`
// = 1) ORDER BY `users`.`user_id` ASC LIMIT 1
fmt.Println(user)
FirstOrCreate
 //FirstOrCreate
        //user2 := demostruct.User{//这里定义的结构体的实例的数值其实就是FirstOrCreate的查询条件
        //	UserId: 2,
        //	Age:    20,
        //	Name:   "菲菲", 
        //	IID:    1,
        //}
        //如果有对应的数据,就查询出来,如果没有对应的数据,就会帮我们创建新的记录
        //db.FirstOrCreate(&user,user2)
        //fmt.Println(user)
Last
 //Last:对应SQL:SELECT * FROM `users`  WHERE (`users`.`user_id` = 1) ORDER BY `users`.`user_id` DESC LIMIT 1
        //db.Debug().Last(&user,1)
        //fmt.Println(user)
Take
    //Take:对应SQL: SELECT * FROM `users`  WHERE (`users`.`user_id` = 1) LIMIT 1
    //db.Debug().Take(&user,1)
    //fmt.Println(user)
Find
//Find:对应SQL:SELECT * FROM `users`  WHERE (`users`.`user_id` = 1)
        user_id_arr := []int{1,2}
        db.Debug().Find(&user,user_id_arr)//SELECT * FROM `users`  WHERE (`users`.`user_id` IN (1,2))  
        fmt.Println(user)
  • 【6】Where:加入指定条件:具体条件为:=,like,in,and,between…:where后的括号中参数和语句必须分开写
  • 【7】Select:筛选查询出来的字段
where
 //db.Debug().Where("user_id = ?",1).First(&user)//没加条件的
        //fmt.Println(user)
        //db.Debug().Where("user_id in (?)",[]int{1,2}).First(&user)
        //fmt.Println(user)//加条件的
select
db.Debug().Select("name,age").Where("user_id = ?",1).First(&user)
        fmt.Println(user)//{0 19 丽丽 0}
        select不写默认全查,写了就只查写的
  • 【8】Create:添加数据
  • 【9】Save:添加数据
Create
    //Create操作只可以插入一条记录,不能批量操作
    //user := demostruct.User{
    //	Age:    26,
    //	Name:   "小明",
    //	IID:    1,
    //}
    //
    //db.Create(&user)
Save
 user := demostruct.User{//可以批量添加
                Age:    14,
                Name:   "莎莎",
                IID:    1,
        }
        db.Save(&user)
Update

更新数据:必须先查询放到参数中才能在更新

  //更新:先查询再更新:
        var user demostruct.User
        //(1)先查询,再通过Model进行操作,再Update操作:
        //db.Where("user_id = ?",1).First(&user)
        //db.Model(&user).Update("age",29)
        //(2)直接在查询之后进行操作:
        db.Where("user_id = ?",1).First(&user).Update("name","露露")
        
        //(3)直接在查询之后进行操作,传入结构体示例,更新多个字段
        db.Where("user_id = ?",1).First(&user).Update(demostruct.User{
                Age:    11,
                Name:   "小刚",
        })
        //(4)直接在查询之后进行操作,传入map,更新多个字段
        db.Where("user_id = ?",1).First(&user).Update(map[string]interface{}{
                "age" : 21,
                "name" : "小花",
        })

四选一就行了,结果都是一样的,第二个就挺不错

Delete

删除数据

   //Delete:删除数据:
        // (1)先查询再删除:
        //var user demostruct.User
        //db.Where("user_id = ?",1).First(&user)
        //db.Delete(&user)
        删除id=1的数据
        
        //(2)通过条件直接进行删除:
        var user demostruct.User
        db.Where("user_id = ?",2).Delete(&user)
        删除id=2的数据

第二个更简单

Not

Not 方法用于创建一个条件,表示某个条件的相反条件。

  • 例如,如果你有一个查询条件为 db.Where("name = ?", "John"),你可以使用 Not 来获取名字不是 “John” 的记录:db.Not("name = ?", "John")

  • db.Not("name = ?", "John").Find(&users)
    
    
Or

可以将多个条件连接在一起

db.Where("name = ?", "John").Or("age > ?", 25)
查询名字为 "John" 或者年龄大于 25 岁的用户记录
Order

用于指定查询结果的排序顺序

// 按照名字降序排列
db.Order("name desc").Find(&users)
limit

指定获取数据的最大数量

// 示例:限制查询结果为10条记录
db.Limit(10).Find(&users)
Offset

用于指定从查询结果的哪一行开始返回记录。

// 示例:从第6条记录开始返回结果
db.Offset(5).Find(&users)
Scan
  • Scan方法用于将查询结果扫描到指定的结构体中。
  • 通常在执行查询后,使用Scan将结果映射到相应的Go结构体。
// 示例:将查询结果映射到User结构体中,容易输出和使用
var user User
db.Where("name = ?", "John").First(&user).Scan(&user)
count
  • Count 方法用于计算符合指定条件的记录总数。
  • 例如,db.Model(&User{}).Where("age > ?", 18).Count(&count) 将返回满足条件的年龄大于 18 的用户记录总数,并将结果存储在 count 变量中。
// 示例:计算年龄大于18的用户记录总数
var count int64
db.Model(&User{}).Where("age > ?", 18).Count(&count)

简例:查询有多少条数据
	var user []demostruct.User//定义
	var count int   //定义count存放数量
	db.Find(&user).Count(&count)  //用FInd查询数据的数量
	fmt.Println(user)  //[{1 19 露露 1} {2 20 绯绯 1} {3 23 拉拉 2}]
	fmt.Println(count) //3
group
  • Group 方法用于指定查询结果的分组方式。
  • 例如,db.Model(&Order{}).Select("status, COUNT(*)").Group("status").Find(&result) 将按订单状态分组,并返回每个状态的订单数量。
// 示例:按订单状态分组,并返回每个状态的订单数量
var result []struct {
    Status string
    Count  int
}
db.Model(&Order{}).Select("status, COUNT(*)").Group("status").Find(&result)
简例:按不同年龄分类,并返回不同年龄人的数量
	var user []demostruct.User
	type data struct {
		Age   int
		Count int
	}
	var c []data
	db.Debug().Select("age,count(*) as count").Group("age").Find(&user).Scan(&c)
	fmt.Println(user)
	fmt.Println(c)
	输出:
	[{0 19  0} {0 23  0}]
[{19 2} {23 1}]

having
  • Having 方法用于在分组的基础上进一步过滤数据。
  • 例如,db.Model(&Order{}).Select("status, COUNT(*)").Group("status").Having("COUNT(*) > ?", 10).Find(&result) 将返回订单数量大于 10 的每个状态。
// 示例:返回订单数量大于10的每个状态
var result []struct {
    Status string
    Count  int
}
db.Model(&Order{}).Select("status, COUNT(*)").Group("status").Having("COUNT(*) > ?", 10).Find(&result)

简例 :在group基础上分组,筛选出年龄大于18的
db.Debug().Select("age,count(*) as count").
		Group("age").Find(&user).Having("age>18").Scan(&c)
	fmt.Println(user)
	fmt.Println(c)
	输出:
	[{0 19  0} {0 23  0}]
    [{23 1}]

Join

Join 用于在查询中关联其他表的数据,最常用的方法是joins

先上示例:

type NewUserInfo struct {//定义新的结构体用于scan,存储 Join 后的结果。
    User_Id int
    Name    string
    I_Id    int
    Info_Id int
    Address string
}
var newUser []NewUserInfo// 创建一个切片,用于存储 Join 操作后的结果集
var users []demostruct.User//创建一个切片,用于存储查询 users 表的结果集。
db.Debug().Select("users.user_id,users.name,users.i_id,user_infos.info_id,user_infos.address").Joins("left join user_infos on users.i_id = user_infos.info_id").Find(&users).Scan(&newUser)  
//逐个分析:前一部分使用 Select 方法指定了要查询的字段,
后半部分使用Joins方法关联了 users 表和 user_infos 表,关联条件为:users.i_id =user_infos.info_id。
Find(&users): 执行查询操作,将结果存储到 users 切片中。
Scan(&newUser): 将查询结果映射到 newUser 切片中的 NewUserInfo 结构体。
fmt.Println(users)
fmt.Println(newUser)
这段代码使用 GORM 进行 JOIN 操作,关联了 users 表和 user_infos 表,最后将结果映射到一个新的结构体 NewUserInfo 和一个切片 newUser 中。
logmod

Gorm内置的日志记录器,显示详细日志

PS :利用Debug只能逐条打印对应日志信息,但是设置LogMod(true)相当于设置了全局打印,所有执行的逻辑日志都会帮我们输出打印

    //开启打印日志:
    db.LogMode(true)

原生sql语句:

//查询操作:Raw
        //var users []demostruct.User
        //db.Raw("select * from users where age = ?",14).Find(&users)
        //fmt.Println(users)
        //增加、删除、修改 :Exec
        //db.Exec("insert into users (age,name) values (?,?)",33,"莹莹")
        //db.Exec("delete from users where user_id = ?",1)
        //db.Exec("update users set name = ? where user_id = ?","明明",3)

大致就是这些,欢迎一起讨论学习

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
gorm scopes是Golang中使用的一种功能,用定义和应用查询作用域。它可以帮助我们在查询数据库时,根据不同的条件和需求,动态地构建查询语句。 使用gorm scopes,我们可以将一组查询条件封装成一个作用域(scope),然后在需要的时候应用到查询中。这样可以使代码更加模块化和可复用,同时也能提高查询的灵活性和可读性。 在gorm中,我们可以通过定义结构体的方法来创建作用域。这些方法需要接收一个gorm.DB类型的参数,并返回一个gorm.DB类型的结果。在方法内部,我们可以使用gorm提供的各种查询方法来构建查询条件,例如Where、Order、Limit等。 下面是一个使用gorm scopes的示例: ```go type User struct { ID uint Name string Age int } func (db *gorm.DB) AgeGreaterThan(age int) *gorm.DB { return db.Where("age > ?", age) } func main() { db, err := gorm.Open("mysql", "user:password@tcp(localhost:3306)/database") if err != nil { panic(err) } defer db.Close() var users []User db.Scopes(db.AgeGreaterThan(18)).Find(&users) } ``` 在上面的示例中,我们定义了一个名为AgeGreaterThan的作用域,它接收一个年龄参数,并返回一个添加了查询条件的gorm.DB对象。然后,在main函数中,我们通过调用Scopes方法并传入AgeGreaterThan作用域,来应用该作用域到查询中。 这样,最终执行的查询语句将会是`SELECT * FROM users WHERE age > 18`,并将结果存储到users变量中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值