带你快速上手gorm一一基础知识汇总

gorm的引入

orm

即Object-Relational Mapping,它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了。

image-20231104154821181

gorm

gorm 是 go语言的一个orm框架,golang写的,开发人员友好的orm库、

中文文档

GORM官方中文文档

安装gorm命令

go get github.com/jinzhu/gorm

// 下面这个 有时候需要, 有时候不需要
go get github.com/jinzhu/gorm/dialects/mysql@v1.9.16

gorm连接数据库

特别是这里导入的第二包,可以不用,但是不能没有

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql" // 引入mysql驱动
)

func main() {
	// 1. 连接数据库。。
	//  第一个参数: 指定要连接的数据库
	// 第二个参数: 指的是数据库的设置信息: 用户名:密码@tcp(ip:端口号)/数据库名字?charset = utf8 & parseTime = True & loc = Local
	// charset = utf8 设置字符集
	// parseTime = True 为了处理time.Time
	// loc = Local 时区设置,与本地时区保持一致
	db, err := gorm.Open("mysql", "root:zhubao@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")

	if err != nil {
		panic(err) // 如果出错,后续代码 没有必要执行,让程序中断
	}
	// 数据库资源的释放:
	defer db.Close()

}

补充二代gorm引入

import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/redis/go-redis/v9"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

var Conn *gorm.DB

var Rdb *redis.Client

func NewMysql()  {
	my := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=True&loc=Local","root","zhubao","127.0.0.1:3306","vote")
	conn ,err := gorm.Open(mysql.Open(my), &gorm.Config{})
	if err != nil {
		fmt.Printf("err:%s\n", err)
		panic(err)
	}
	Conn = conn
}

对表进行操作

创建表

// 定义结构体:
type User struct {
	Age  int
	Name string
}
// 创建表:通常情况下,数据库中新建的表的名字是结构体名字的小写复数形式,例如,结构体User,表名 users
	db.CreateTable(&User{})
// 这种情况,可以 自己设定表的名字。
	db.Table("user").CreateTable(&User{})

删除表

// 通过 &User{} 指定结构体,删除对应的表
	db.DropTable(&User{})
// 通过指定 表名 删除对应的表
	db.DropTable("users")

判断表是否存在

flag := db.HasTable(&User{})
flag1 := db.HasTable("user")
fmt.Println(flag, flag1) // 输出 true true

自定义表名

type User struct {
	Age  int
	Name string
}

db.CreateTable(&User{})

func (User) TableName() string { // 给对应结构体返回的表 命名
	return "user"
}

数据增删改查

增加 : 要先创建对应表结构的 结构体,然后创建一个表映射函数,确定是哪个表,然后进行 添加

可以用 RecordNotFound 函数来确定查询结果是否为空

// 定义结构体:
type User struct {
	Age  int
	Name string
}

func main() {

	db, err := gorm.Open("mysql", "root:zhubao@tcp(localhost:3306)/testgormcharset=utf8&parseTime=True&loc=Local")

	if err != nil {
		panic(err) // 如果出错,后续代码 没有必要执行,让程序中断
	}
	// 数据库资源的释放:
	defer db.Close()

	// 增加
	db.Create(&User{
		Age:  18,
		Name: "张三",
	})

    // 查询数据 : 第一个参数: 查询出来的数据的载体:
	var myuser User
	db.First(&myuser, "age = ?", 19)
	fmt.Println(myuser)
    
    // 更新数据
	db.Model(&myuser).Update("age", 626)
	db.Model(&myuser).Update("name", "菲菲")
    
    //删除数据
	db.Delete(&myuser)

}

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

模型名和表名的映射规则

image-20231104201158745

gorm.Modle匿名字段

在模型中添加 gorm.Mode匿名字段,就自动会在生成的数据库表中添加四个字段

ID : 主键自增长

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

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

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

type Student struct {
	gorm.Model
	Age  int
	Name string
}

db.CreateTable(&Student{})   // 这样就创建出来了下面图片这样的表

image-20231104202952547

结构体标签(字段约束)

通过结构体标签gorm实现对 一些字段的约束

(1) - : 忽略,不映射这个字段 gorm:"-"

(2) primary_key:主键 eg: gorm:"primary_key"

(3)AUTO_INCREMENT:自增 eg: 'gorm:“AUTO_INCREMENT”

(4) not null:不为空,默认为空 eg: 'gorm:“not null”

(5)index: 索引 eg:gorm:"index"

​ 创建索引并命名: eg: gorm:"unique_index"

(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)type : 设置sql类型 eg:gorm:"type:int"

type Student struct {
	Id    int    `gorm:"primary_key;AUTO_INCREMENT"`
	Age   int    `gorm:"not null"`
	Name  string `gorm:"index:uname"` // 索引值可以自定义
	DECS  string `gorm:"-"`
	Stuid int    `gorm:"unique"`
	Class string `gorm:"column:grade"`
	Lover string `gorm:"size:25"`
	Loser string `gorm:"type:int"`
}

表关系

一对一

image-20231104213308144

一对多

image-20231104213900169

多对多

image-20231104215558808

一对一关系

关联添加

type User struct {
	UserId int `gorm:"primary_key;AUTO_INCREMENT"`
	Age    int
	Name   string
	// 指定外键
	IID int
}

type UserInfor struct {
	InforID int `gorm:"primary_key;AUTO_INCREMENT"` // 添加数据的时候,不用管主键
	Pic     string
	Address string
	Email   string
	// 关联关系
	User User `gorm:"ForeignKey:IID;AssociationForeignKey:InforID"`
}

infor := UserInfor{
		Pic:     "imgload",
		Address: "河南省",
		Email:   "123456@qq.com",
		User: User{
			Age:  18,
			Name: "张三",
		},
	}

关联查询

Associaion方式

先First查询,再Associatiion查询

//  关联查询操作: (关联关系在UserInfor表中,所以从UserInfor入手)
var userinformation UserInfor
//  如果只是执行下面这步操作, 那么关联的User信息时查询不到了
db.First(&userinformation, "infor_id=?", 1)
fmt.Println(userinformation) // 输出:{1 imgload 河南省 123456@qq.com {0 0  0}}

// 如果想要查询到 User相关内容,则应该:
// Model参数: 要查询的表数据,Association参数:关联到的具体的模型: 模型名字为 User (字段名字)
// Find 参数: 查询的结果要存放在什么字段中。 这里是 存在到了userinformation 中的User字段
db.Model(&userinformation).Association("User").Find(&userinformation.User)
fmt.Println(userinformation)

Preload方式

感觉比较方便

var userinfor1 UserInfor
// 查询 address = 河南省 的数据放入到 userinfor1中,并且查询中 要关联User表
db.Preload("User").Find(&userinfor1, "address = ?", "河南省")
fmt.Println(userinfor1)

Related方式

这种情况下,是将关联表的数据,单独查出来

var userinfor2 UserInfor
db.First(&userinfor2, "address=?", "河南省")
fmt.Println(userinfor2)  // 输出 {1 imgload 河南省 123456@qq.com {0 0  0}}

var user1 User
db.Model(&userinfor2).Related(&user1, "User")
fmt.Println(user1)  // 输出 {1 18 张三 1}
fmt.Println(userinfor2)  // 输出 {1 imgload 河南省 123456@qq.com {0 0  0}}

关联修改

//  先获取数据
var userinfor5 UserInfor
db.Preload("User").Find(&userinfor5, "address = ?", "河南省")
fmt.Println(userinfor5) // 输出 {1 图片路径 河南省 123456@qq.com {1 88 张三 1}}
// 在进行更新   如果需要修改关联表这里需要 .user . 如果不需要修改关联表,则不修改 .user
db.Model(&userinfor5.User).Update("age", 18)
fmt.Println(userinfor5) // 输出 {1 图片路径 河南省 123456@qq.com {1 18 张三 1}}

关联删除

先查询再删除

目前是只能删除整个表的信息,没有发现怎么删除某个字段的信息(可以尝试进行字段修改为空吗? “ “ 有待后续发现!)

var userinfor5 UserInfor
db.Preload("User").Find(&userinfor5, "address = ?", "地址")
fmt.Println(userinfor5)
db.Delete(&userinfor5.User)
fmt.Println(userinfor5)

一对多关系

关联增加

package main

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql" // 引入mysql驱动
)

type Author struct {
	AID  int
	Name string
	Age  int
	Sex  string
	// 关联关系
	Article []Article `gorm:"ForeignKey:AuId;AssociationForeignKey:AID"`
}

type Article struct {
	ArID    int
	Title   string
	Content string
	Desc    string
	// 设置外键:
	AuId int
}

func main() {
	db, err := gorm.Open("mysql", "root:zhubao@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
	if err != nil {
		panic(err)
	}

	defer db.Close()

	db.CreateTable(&Author{})
	db.CreateTable(&Article{})

	person := Author{
		Name: "张三",
		Age:  18,
		Sex:  "男",
		Article: []Article{
			{
				Title:   "HTML入门",
				Content: "内容1****",
				Desc:    "非常好1***",
			},
			{
				Title:   "CSS入门",
				Content: "内容2***",
				Desc:    "非常好2****",
			},
		},
	}

	db.Create(&person)

}

关联查询

查询方式和上面一对一关系的查询基本一样。

Associaition方式

var authors Author
db.First(&authors, "name = ?", "张三")
fmt.Println(authors)
db.Model(&authors).Association("Article").Find(&authors.Article)
fmt.Println(authors)

Preload方式

var authors Author

db.Preload("Article").Find(&authors, "a_id = ?", 0)

Related方式

目前仅这种方法没报错!实现过程可参考上面一对一关系中的查询

var authors Author
db.First(&authors, "name=?", "张三")
fmt.Println(authors)

var aubooks Article
db.Model(&authors).Related(&aubooks, "Article")
fmt.Println(aubooks)

关联修改

先查询出来再进行修改

var authors Author
db.Preload("Article").Find(&authors, "name = ?", "张三")
fmt.Println(authors)
db.Model(&authors.Article).Where("ar_id = ?", 2).Update("title", "JS入门")

关联删除

先查询再删除

db.Preload("Article").Find(&authors, "name = ?", "张三")
db.Where("ar_id = ?", 2).Delete(&authors.Article)

多对多关系

添加操作

    package main

    import (
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql" // 引入mysql驱动
    )

    type Student struct {
    SId    int `gorm:"primary_key"`
    SNo    int
    Name   string
    Sex    string
    Age    int
    Course []Course `gorm:"many2many:Student2Course"`
    }

    type Course struct {
    CId         int `gorm:"primary_key"`
    CName       string
    TeacherName string
    Room        string
    }

    func main() {
    db, err := gorm.Open("mysql", "root:zhubao@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()

    db.CreateTable(&Student{})
    db.CreateTable(&Course{})

    stu := Student{
        SNo:  1001,
        Name: "张三",
        Sex:  "男",
        Age:  18,
        Course: []Course{
            {
                CName:       "数据结构",
                TeacherName: "老王",
                Room:        "0#508",
            },
            {
                CName:       "计算机网络",
                TeacherName: "老张",
                Room:        "0#608",
            },
        },
    }

    db.Create(&stu)

   }

删改查

和上面两种关系操作步骤一样,可参考上面!

常用方法

方法1 (查找数据)

像下面这四种方法,其中 ()中那么1也可以换成具体查询条件。比如(&stu,“name = ?”,“张三”)

First

将查询出来的结果,升序排列 (只能查出来第一条数据)

var stu Student
//  SELECT * FROM `students`  WHERE (`students`.`id` = 1) ORDER BY `students`.`id` ASC LIMIT 1  
db.Debug().First(&stu, 1) 
fmt.Println(stu)

FirstOrCreate

根据指定条件进行查询,但是只能查出来第一条数据

如果没有被查询的数据,那么就会自动添加一条数据

user := Student{
    Age: 18,
}

var stu Student
// SELECT * FROM `students`  WHERE (`students`.`age` = 18) ORDER BY `students`.`id` ASC LIMIT 1  
db.Debug().FirstOrCreate(&stu, user)
fmt.Println(stu)

Last

这是将查询结构降序排列,只能查第一个

//SELECT * FROM `students`  WHERE (`students`.`id` = 1) ORDER BY `students`.`id` DESC LIMIT 1
db.Debug().Last(&stu, 1)
fmt.Println(stu)

Take

直接查出结果,不进行排序 。 只能查第一个

// SELECT * FROM `students`  WHERE (`students`.`id` = 1) LIMIT 1 
db.Debug().Take(&stu, 1)
fmt.Println(stu)

Find

这个是根据条件查的。 考虑一下是否能一次查出来多条数据?

//  SELECT * FROM `students`  WHERE (age = 18)  
db.Debug().Find(&stu, "age = ?", 18)
fmt.Println(stu)

where

根据指定条件进行查询

// SELECT * FROM `students`  WHERE (id = 1) LIMIT 1  
db.Debug().Where("id = ?", 1).First(&stu)
fmt.Println(stu)

select

查询指定字段

// SELECT name,age FROM `students`  WHERE (id = 1) LIMIT 1 
db.Debug().Select("name,age").Where("id = ?", 1).First(&stu)
fmt.Println(stu)

方法2(添加数据)

Create

只能插入一条数据,不能批量操作

db.Debug().Create(&Student{
    Name: "老八",
    Sex:  "男",
    Age:  66,
})

Save

也是插入一条数据,用法感觉和上面的Create一样。

db.Debug().Save(&Student{
    Name: "王凤霞",
    Sex:  "女",
    Age:  22,
})

方法3(修改数据)

Model

先查询后修改

var user Student
db.Where("id = ? ", 1).First(&user)
db.Model(&user).Update("age", 19)

Update

直接修改 (实质还是在查询后修改)

db.Where("id = ?", 1).First(&user).Update("age", 18)

直接一次修改多个(实质还是先查询后修改)

db.Where("id =?", 1).First(&user).Update(Student{  // 传入结构体实例
    Age:  25,
    Name: "老八",
})

这个是用Map键值对的方法修改多个数据,但是目前没有发现与上面那个有什么区别

db.Where("id =?", 1).First(&user).Update(map[string]interface{}{
    "age":  50,
    "name": "小花花",
})

方法4(删除操作)

Delete

(1)先查询 后 删除

db.Where("id = ?", 1).First(&user)
db.Delete(&user)

(2)根据指定条件直接删除

db.Where("id = ?", 3).Delete(&user)

Not 、Or 、 Order的使用

Not

not后面那个括号中 可以添加多个判断条件。 (多个判断条件通过结构体形式传送)

var users []Student
db.Not("id = ?", 2).Find(&users) // 查询所有 id 不等于2的
fmt.Println(users)

Or

可以同时并列多个条件。

db.Where("id = ?", 4).Or("id = ?", 5).Find(&users)

Order

让查询结果排序. desc是降序,asc是升序

db.Where("sex = ?", "女").Order("id desc").Find(&users)

Limit、Offset、Scan的使用

Limit

limit是限制查询数量的,就比如这个sql语句只能查出来两个记录

db.Limit(2).Find(&users)

Offset

设置偏移量,就比如正常数据都是从第一条开始的,这里可以设置偏移,让从第二条或者第三条等等开始查

注意:Offset必须和Limit结合使用

db.Offset(2).Limit(1).Find(&users) // 设置偏移量为2,并且仅查一条数据

Scan

这个就是将查询的结果全部复制给另一个结构体。下面这个例子是将查询出来的结果传给demo。

但是 这个代码目前不生效 不知道为什么!!!

type Demo struct {
    name string
    sex  string
    age  int
}

var demo Demo
var user Student
db.Where("id = ?", 2).Find(&user).Scan(&demo)
fmt.Println(user)
fmt.Println(demo)

Count

就是记录一下查询结果的数量

db.Find(&users).Count(&count)

左、右连接

左连接

将查询出来的数据, 通过扫描传给一个新的结构体 理解的不是太透彻!!!

type NewUser struct {
    User_id  int
    Name     string
    Infor_id int
    Address  string
}

var newUser []NewUser
var users []User
db.Debug().Select("users.user_id,users.name,user_infos.infor_id,user_infos.address").Joins("left join user_infos on users.i_id = user_infos.infor_id").Find(&users).Scan(&newUser)
fmt.Println(users)
fmt.Println(newUser)

LogMode

开启全局 类似于 debug的功能,每次执行都能看见sql语句

db.LogMode(true)

原生sql语句

查询操作

var users []User
db.Raw("select * from users ").Find(&users)
fmt.Println(users)

增加、删除、修改

//  增加
db.Exec("insert into users(user_id,age,name,i_id) values (?,?,?,?)", 6, 30, "王老万", 2)
// 修改
db.Exec("update users set name=? where user_id = ?", "小林子", 6)
//  删除
db.Exec("delete from users where user_id = ?", 6)
  • 23
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值