Go开源宝藏GORM 专场 (含思维导图) | 持续更新

Posted 小生凡一

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go开源宝藏GORM 专场 (含思维导图) | 持续更新相关的知识,希望对你有一定的参考价值。

写在前面

本人只是一个Go语言的初学者,这篇文只是把我平常经常用到的都总结起来而已。
具体详细的内容建议到去GORM的中文文档查看。
当然这篇文章也会持续更新,记录我的CURD打磨过程
这篇文章也会持续更新哒

思维导图

1. 简介

  • 介绍:一个Go语言开发的ORM库,是字节的一位大牛写哒!!国产框架!
  • 下载:go get -u github.com/jinzhu/gorm

流程:

  1. 导入Gorm
  2. 导入数据库驱动
  3. 定义数据库模型
  4. 与数据库连接
  5. 字段迁移映射
  6. 增、删、改、查
  7. 关闭数据库连接

2. 数据库驱动

数据库驱动导入
mysqlgithub.com/go-sql-driver/mysqlgithub.com/jinzhu/gorm/dialects/mysql
postgresqlgithub.com/lib/pqgithub.com/jinzhu/gorm/dialects/postgres
sqlitegithub.com/mattn/go-sqlite3github.com/jinzhu/gorm/dialects/sqlite
sqlservergithub.com/jinzhu/gorm/dialects/mssql

3. 连接(MySQL为例子)

配置ini文件

[mysql]
Db = mysql
DbHost = 127.0.0.1
DbPort = 3306
DbUser = root
DbPassWord = root
DbName = carsys

读取配置文件

	file, err := ini.Load("./conf/config.ini")
	if err != nil {
		fmt.Println("配置文件读取错误,请检查文件路径:", err)
	}
	LoadMysqlData(file)

数据库路径拼接

path := strings.Join([]string{DbUser, ":", DbPassWord, "@tcp(", DbHost, ":", DbPort, ")/", DbName, "?charset=utf8&parseTime=true"}, "")  // 路径拼接
model.Database(path)  	// 连接数据库

连接数据库,这个是放在了model包,所以后面的操作都是model.DB

var DB *gorm.DB  //全局的数据库入口

func Database(connString string) {
	db, err := gorm.Open("mysql", connString)
	db.LogMode(true)
	if err != nil {
		panic(err)
	}
	if gin.Mode() == "release" {
		db.LogMode(false)
	}
	db.SingularTable(true)         //默认不加复数s,不然他的每个数据后面都会加上和s比如user变成users
	db.DB().SetMaxIdleConns(20)  	//设置连接池,空闲
	db.DB().SetMaxOpenConns(100) 	//设置打开最大连接
	db.DB().SetConnMaxLifetime(time.Second * 30)
	DB = db
	migration() //模型迁移映射到数据库
}

4. 迁移(MySQL为例子)

自动迁移数据库到最新版本,最会添加列和索引,不会修改类型删除列

4.1 构建数据库表

这个gorm.Model是自动加上create_timeupdate_timedelete_time

查看源码里面得gorm中得model

然后我们可以像这样直接去定义一个struct模型,准备映射到数据库中,就不用写sql语句了。
后面可以加上tag就像是gorm:"unique"这样的,表示这个是唯一的。

import "github.com/jinzhu/gorm"

type User struct {
	gorm.Model
	UserName       string `gorm:"unique"` 
	Email          string 
	PasswordDigest string
	Nickname       string `gorm:"unique"`
	Status         string
	Limit          int   // 0 非管理员  1 管理员
	Type           int    // 0表示用户  1表示商家
	Avatar         string `gorm:"size:1000"`
	Monery 		    int
}

4.2 数据库模型迁移

gorm提供了一个AutoMigrate的方法,很方便地进行映射迁移的工作。

func migration() {
	//自动迁移模式
	DB.Set("gorm:table_options", "charset=utf8mb4").
		AutoMigrate(&User{})
}

4.3 tags束缚

4.3.1 一对多

语义场景:评论和帖子的关系。一个帖子有很多的评论,但是这个评论只能在这个帖子下面。

所以可以通过foreignkey进行外键的束缚。外键到Social这个模型。关系标识为social_id

type Comment struct {
	gorm.Model
	Content    string
	ParentId   uint   	// 父评论ID
	UserID     uint   	// 用户ID
	ReplyName  string 	// 回复者名字
	UserName   string
	UserAvatar string
	SocialId   uint  `gorm:"foreignkey:Social;association_jointable_foreignkey:social_id"` //社区帖子ID
	Children   []Comment `gorm:"foreignkey:ParentId"`
}

4.3.2 多对多

语义环境:一个用户可以有多个好友,反过来也可以。所以就是user表自己的多对多。

使用tags是many2many

type User struct {
	gorm.Model
	Relations 	   []User `gorm:"many2many:relation; association_jointable_foreignkey:relation_id"`
	UserName       string
	Email          string 	//`gorm:"unique"`
	Avatar         string 	`gorm:"size:1000"`
	Phone 		   string
	BanTime 	   int
	OpenID 		   string 	`gorm:"unique"`
}

这样的多对多的关联,就会多创建一个表来存两者的关系。


5. 增

5.1 一对一

create函数进行创建。

category := model.Category{
		CategoryName: service.CategoryName,
		EnglishName:service.EnglishName,
}
err := model.DB.Create(&category).Error

5.2 一对多

语义环境:这里就是一评论表,socialId就是帖子, 一个帖子对应多个评论,和一对一是 一样的创建方式

	var comment model.Comment
	comment = model.Comment{
		UserID:    user.ID,
		Content:   service.Content,
		ParentId:  service.ParentId,
		UserName:  user.UserName,
		UserAvatar:  user.Avatar,
		SocialId: service.SocialID,
	}
	err := model.DB.Create(&comment).Error

5.3 多对多

语义环境:用户表,用户和用户之间建立多对多联系

type User struct {
	gorm.Model
	Relations 	   []User `gorm:"many2many:relation; association_jointable_foreignkey:relation_id"`
	UserName       string
	Email          string 	//`gorm:"unique"`
	Avatar         string 	`gorm:"size:1000"`
	Phone 		   string
	BanTime 	   int
	OpenID 		   string 	`gorm:"unique"`
}

选出user表中的两个元素。然后进行关联绑定。

	var user model.User
	var friend model.User
	model.DB.Model(&friend).Where(`id = ? `,id).First(&friend)  			//被关注者
	model.DB.Model(&user).Where(`id = ?`,userId).First(&user)			//关注者
	err := model.DB.Model(&user).Association(`Relations`).Append([]model.User{friend}).Error

这条语句就是把这个user和这个friend建立联系,存放在Relations表里面。


6. 删

6.1 一对一

GORM中的delete删除是软删除,就是虽然是删除了,但是并没有完全删除,而是保留在数据中但是查询并不查询这条已经删除的语句。

  • 单记录删除

先找到这条数据

	var social model.Society
	code := e.Success
	err := model.DB.First(&social, id).Error // 根据id找到这个social,记得传地址。

然后进行删除即可

	err = model.DB.Delete(&social).Error
  • 批量删除
 db.Where("user_name like ? ","%Fan%").Delete(User{})
  • 永久删除:在数据库直接清空了,不是软删除了
db.Unscoped().Where("name Like ?","%6%").Delete(User{})

6.2 一对多

其实一对一就是特殊的一对多

删除和一对一其实是一样的操作。

	var social model.Society
	model.DB.First(&social, id)  // 找到这个帖子
	model.DB.Delete(&social)   // 将其进行删除

6.3 多对多

找到这两者的关系,然后进行关联删除即可。就会从Relations表中把这两者的关系进行删除。

	var user model.User
	var friend []model.User
	model.DB.Model(&friend).Where(`id = ?`,id).First(&friend)  			//被关注者
	model.DB.Model(&user).Where(`id = ?`,userId).First(&user)	//关注者
	err := model.DB.Model(&user).Association(`Relations`).Delete(friend).Error

7. 改

7.1 一对一

  • Save
    会保存所有的字段,即使字段是零值
social := model.Society{
		CategoryID:    service.CategoryID,
		Title:         service.Title,
		Content:       service.Content,
		Picture:       service.Picture,
		CategoryName:  service.CategoryName,
	}
err := model.DB.Save(&social).Error
  • Update
    当使用Update更新单个列时,需要指定条件,否则会返回ErrMissingWhereClause错误。
model.DB.Model(model.User{}).Where("open_id=?", openid).Update("phone", phone)
  • Updates

批量更新,只会更新指定字段,但是如果是空值的情况下是不更新的成空值的。

只更新指定字段

model.DB.Table("user").Where("user_name = ?","FanOne").
Updates(map[string]interface{}{"phone":"10001","email":"fanone@qq.com"})

只更新更改的非零值的字段

model.DB.Model(&User{}).Where("user_name = ?","FanOne").
Updates(User{Phone:"10001",Email:"fanone@666.com"})

7.2 一对多

直接更新字段,同上。

7.3 多对多

由于多对多的是根据关系来关联的,所以更新字段关系是无关的,同上。


8. 查

  • First 是找到第一个
  • Last 是找到最后一个
  • Find 是找到全部

8.1 一对一

语义环境:用户表

type User struct {
	gorm.Model
	Relations 	   []User `gorm:"many2many:relation; association_jointable_foreignkey:relation_id"`
	UserName       string
	Email          string 	//`gorm:"unique"`
	Avatar         string 	`gorm:"size:1000"`
	Phone 		      string
	BanTime 	      int
	OpenID 		   string 	`gorm:"unique"`
}

8.1.1 基本查询

  • 查询第一个
var u1 User
db.First(&u1)
fmt.Println(u1)
  • 查询最后一个
var u2 User
db.Last(&u2)
fmt.Println(u2)
  • 按主键获取
var u3 User
db.First(&u3,2) //不指定的话,默认主键是id
fmt.Println(u3)
  • 按条件查询一条
var u4 User
db.First(&u4,"user_name=?","FanOne") //不指定的话,默认主键是id
fmt.Println(u4)
  • 获取所有数据
var u5 []User
db.Find(&u5) //查询所有的数据信息
fmt.Println(u5)

8.1.2 Where条件

  • 单一条件
var u1 User
db.Where("user_name = ?","FanOne").First(&u1)
  • 嵌套查询
var u1s []User
db.Where("user_name=?","fanone").Where("phone=?","10086").Find(&u1s)
  • 多条件
var u2 User
db.Where("user_name = ? AND phone = ?","FanOne","10086").First(&u2)
  • 模糊查询 记得加上%
var u3 User
db.Where("user_name LIKE ?","%Fan%").First(&u3)  //返回第一个user_name与Fan相近的数据
var u3s []User
db.Where("user_name LIKE ?","%Fan%").Find(&u3)   //返回多个user_name与Fan相近的数据
  • 范围查询
var u4 []User
db.Where("id > ?","FanOne","10").Find(&u2) // 找到id>10那部分的数据
  • 数组形式
var u5 []User
db.Where("user_name in (?)",[]string{"Fan","One"}).Find(&u5)
  • 结构体形式
var u6 User
db.Where(&User{UserName:"FanOne"}).First(&u6)
  • map形式
var u7 User
db.Where(map[string]interface{}{"user_name":"fan","phone":"10086"}).First(&u7)

8.1.3 Not条件

  • 查询UserName != FanOne的数据,返回列表
var u1 []User
db.Not(&User{UserName:"FanOne"}).Find(&u1)
  • 查询UserName != FanOne的数据,返回第一条数据
var u2 User
db.Not("user_name","FanOne").First(&u2)
  • 查询UserName != fan的数据,返回第一条数据
var u3 User
db.Not("user_name = ?","fan").First(&u2)
  • 查询 UserName 不在这个字符串列表当中的数据,返回第一条数据
var u4 User
db.Not("user_name",[]string{"fan","one"}).First(&u4)
  • 查询 UserName 不在这个字符串列表当中的数据,返回列表
var u5 []User
db.Not("user_name in (?)",[]string{"fan","one"}).Find(&u5)

8.1.4 选择查询

  • 只查询user_name这一列的数据
var u1 []User
db.Select("user_name").Find(&u1)
  • 只查询user_name和phone这两列的数据,字符串数组形式
var u1 []User
db.Select([]string{"user_name","phone"}).Find(&u1)
  • 只查询user_name和phone这两列的数据,字符串数组形式
var u1 []User
db.Select("user_name , phone").Find(&u1)

8.1.5 排序

默认排序是升序的

var u1s,u2s []User
db.Order("name desc").Find(&u1s)  //按照名字降序
db.Order("name asc",true).Find(&u1s)  //按照名字升序

8.1.6 分页

Limit 页面大小
Offset 页数

var us []User
db.Order("id asc").Offset(5).Limit(3).Find(&us)

8.1.7 数量

var count int
db.Model(&User{}).Count(&count)
var count int
db.Model(&User{}).Where("user_name Like ?","%6%").Count(&count)
var count int
db.Table("users").Where("user_name Like ?","%6%").Count(&count)

8.1.8 原生SQL

当我们要进行比较复杂的查询的时候,可以通过这个原生sql进行查询。进行并查询操作

	query := "SELECT * FROM `work_time` WHERE `work_time`.`deleted_at` IS NULL AND month = "+ `"`+ data.Month +`"`

	if data.Search!="" {
		query += ` AND (( mask LIKE "`+"%"+data.Search +"%"+ `" ) OR ( number LIKE "`+"%"+data.Search+"%"+ `" ))`
	}
	if data.DepartmentName!="" {
		query += " AND department_name LIKE " + `"`+"%" +data.DepartmentName+"%" + `"`
	}
	if data.WorkType!="" {
		query += " AND work_type LIKE " + `"`+"%" +data.WorkType+"%" + `"`
	}
	if data.EmployeeStatus!="" {
		query += " AND employee_status LIKE " + 以上是关于Go开源宝藏GORM 专场 (含思维导图) | 持续更新的主要内容,如果未能解决你的问题,请参考以下文章

Go开源宝藏Golang 爬虫 | 整点新花样

Go实战Gin + Gorm 基于RESTful API 的简单备忘录 | 含接口文档

渗透测试入门到入狱(附思维导图)| 寻找C站宝藏

渗透测试入门到入狱(附思维导图)| 寻找C站宝藏

渗透测试入门到入狱(附思维导图)| 寻找C站宝藏

4个珍藏已久的宝藏资源网站,提高你的工作效率