连接数据库
增加&查询
package main
import (
"fmt"
"gorm.io/gorm"
)
type Student struct {
ID uint `gorm:"size:3"`
Name string `gorm:"size:8"`
Age int `gorm:"size:3"`
Gender bool
Email *string `gorm:"size:32"`
}
func main() {
DB.AutoMigrate(&Student{})
//添加记录
email := "123456"
//批量插入
var studentList []Student
for i := 0; i < 10; i++ {
studentList = append(studentList, Student{
Name: "User" + strconv.Itoa(i+1),
Age: 18,
Gender: true,
Email: &email,
})
}
err := DB.Create(&studentList).Error
fmt.Println(err)
//单条记录的查询
//var student Student
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
DB.Take(&student) //会查第一条数据
DB.First(&student)
fmt.Println(student)
DB.Last(&student)
fmt.Println(student)
fmt.Println(student)
//根据主键查询
DB.Take(&student, 2)
fmt.Println(student)
//查询
DB.Take(&student, "name = ?", "ei")
//查询多条记录
var studentList []Student
count := DB.Find(&studentList).RowsAffected
fmt.Println(count)
//转为json
data, _ := json.Marshal(studentList)
fmt.Println(string(data))
//根据主键列表查询
var studentList []Student
DB.Find(&studentList, []int{2, 4, 6, 8})
fmt.Println(studentList)
//根据其他条件查询
var studentList []Student
DB.Find(&studentList, []int{2, 4, 6, 8})
DB.Find(&studentList, "name in (?)", []string{"User1", "User2"})
fmt.Println(studentList)
}
更新
//sava更新
var student Student
DB.Take(&student, 11)
student.Name = "lin"
DB.Save(&student)
//改多个字段
var studentList []Student
DB.Find(&studentList, []int{9, 10, 11}).Update("gender", false)
//改多行多列
DB.Find(&studentList, []int{9, 10}).Updates(Student{Age: 50, Gender: true})
//使用map
DB.Find(&studentList, []int{9, 10}).Updates(map[string]any{
"name": "in",
})
删除
//删除
var student Student
DB.Delete(&student, 8)
DB.Delete(&student, []int{9, 10})
//先查再删
DB.Take(&student)
DB.Delete(&student)
创建HOOK钩子
func (user *Student) BeforeCreate(tx *gorm.DB) (err error) {
email := "test@qq.com"
user.Email = &email
return nil
}
func main(){
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
DB.Create(&Student{
Name: "six",
Age: 18,
})
}
查询
var users []Student
//查询用户名是枫枫的,存储在users中
DB.Where("name = ?", "枫枫").Find(&users)
fmt.Println(users)
//查询名字不是枫枫的
DB.Where("name <> ?", "枫枫").Find(&users)
fmt.Println(users)
// 查询用户名包含 如燕,李元芳的
DB.Where("name in ?", []string{"如燕", "李元芳"}).Find(&users)
fmt.Println(users)
// 查询姓李的
DB.Where("name like ?", "李%").Find(&users)
fmt.Println(users)
// 查询年龄大于23,是qq邮箱的
DB.Where("age > ? and email like ?", "23", "%@qq.com").Find(&users)
fmt.Println(users)
// 查询是qq邮箱的,或者是女的
DB.Where("gender = ? or email like ?", false, "%@qq.com").Find(&users)
fmt.Println(users)
使用结构体查询
使用结构体会过滤零值,如果是查询条件是零值的话,会不考虑这个条件
并且结构体中的条件都是and关系
//结构体查询会过滤零值
DB.Where(&Student{Name: "元芳", Age: 12}).Find(&users)
fmt.Println(users)
使用map查询
不会过滤零值
//map不会过滤零值
DB.Where(map[string]any{"name": "元芳", "age": 0}).Find(&users)
fmt.Println(users)
Not
// 排除年龄大于23的
DB.Not("age > 23").Find(&users)
fmt.Println(users)
Or
DB.Or("gender = ?", false).Or(" email like ?", "%@qq.com").Find(&users)
fmt.Println(users)
Select
没有被选中,会被赋零值
DB.Select("name", "age").Find(&users)
fmt.Println(users)
//也可以存入另一个结构体中
type User struct {
Name string
Age int
}
var students []Student
var users []User
DB.Select("name", "age").Find(&students).Scan(&users)
fmt.Println(users)
//这样会查询两次
查询一次的话有两种方法
var users []User
DB.Model(&Student{}).Select("name", "age").Scan(&users)
fmt.Println(users)
var users []User
DB.Table("student").Select("name", "age").Scan(&users)
fmt.Println(users)
排序
var users []Student
DB.Order("age desc").Find(&users)
fmt.Println(users)
// desc 降序
// asc 升序
分页查询
var users []Student
// 一页两条,第1页
DB.Limit(2).Offset(0).Find(&users)
fmt.Println(users)
// 第2页
DB.Limit(2).Offset(2).Find(&users)
fmt.Println(users)
// 第3页
DB.Limit(2).Offset(4).Find(&users)
fmt.Println(users)
更通用的方法
var users []Student
//一页多少条
limit := 2
//第几页
page := 1
offset := (page - 1) * limit
DB.Limit(limit).Offset(offset).Find(&users)
fmt.Println(users)
加个for循环打印出所有的
var users []Student
limit := 2 // 每页多少条
page := 1 // 从第一页开始
offset := 0 // 偏移量
for {
// 计算偏移量
offset = (page - 1) * limit
// 查询当前页的数据
DB.Limit(limit).Offset(offset).Find(&users)
// 如果当前页没有数据了,说明已经查询完所有数据
if len(users) == 0 {
break
}
// 打印当前页的数据
fmt.Println(users)
// 清空切片,准备下一次查询
users = []Student{}
// 增加页码
page++
}
去重
//去重
var ageList []int
DB.Table("students").Select("age").Distinct("age").Scan(&ageList)
//或者
//DB.Table("students").Select("distinct age").Scan(&ageList)
fmt.Println(ageList)
分组查询
//查询男生的人数和女生的个数
var ageList []int
DB.Table("students").Select("count(id)").Group("gender").Scan(&ageList)
fmt.Println(ageList)
//精确一点
type AggeGroup struct {
Gender int
Count int `gorm:"column:count(id)"`
}
var agge []AggeGroup
//查询男生的个数和女生的个数
DB.Table("students").Select("count(id)", "gender").Group("gender").Scan(&agge)
fmt.Println(agge)
//更精确一点
type AggeGroup struct {
Gender int
Count int `gorm:"column:count(id)"`
Name string `gorm:"column:group_concat(name)"`
}
//GROUP_CONCAT是 MySQL 中的一个聚合函数,用于将分组内的某个字段值连接成一个字符串
var agge []AggeGroup
//查询男生的个数和女生的个数
DB.Table("students").Select("count(id)", "gender", "group_concat(name)").Group("gender").Scan(&agge)
fmt.Println(agge)
执行原生sql
type AggeGroup struct {
Gender int
Count int `gorm:"column:count(id)"`
Name string `gorm:"column:group_concat(name)"`
}
var agge []AggeGroup
DB.Raw(`SELECT count(id), gender, group_concat(name) FROM students GROUP BY gender`).Scan(&agge)
fmt.Println(agge)
子查询
# 原生sql
select * from students where age > (select avg(age) from students);
//相当于
var users []Student
DB.Model(Student{}).Where("age > (?)", DB.Model(Student{}).Select("avg(age)")).Find(&users)
fmt.Println(users)
命名参数
var users []Student
DB.Where("name = @name and age = @age", sql.Named("name", "枫枫"), sql.Named("age", 23)).Find(&users)
DB.Where("name = @name and age = @age", map[string]any{"name": "枫枫", "age": 23}).Find(&users)
fmt.Println(users)
Find到map
var res []map[string]any
DB.Table("students").Find(&res)
fmt.Println(res)
查询引用scope
可以再model层写一些通用的查询方式,这样外界就可以直接调用方法即可
func Age23(db *gorm.DB) *gorm.DB {
return db.Where("age > ?", 23)
}
func main(){
var users []Student
DB.Scopes(Age23).Find(&users)
fmt.Println(users)
}
一对多关系
创建表
type User struct {
ID uint
Name string `gorm:"size:8"`
Articles []Article
}
type Article struct {
ID uint
Title string `gorm:"size:16"`
UserID uint
User User
}
func main() {
//创建表
DB.Debug().AutoMigrate(&User{}, &Article{})
}
//删除表
DB.Debug().Migrator().DropTable(&User{})
创建&关联数据
//创建用户,带上文章
DB.Create(&User{
Name: "枫枫",
Articles: []Article{
{
Title: "python",
},
{
Title: "golang",
},
},
})
//创建文章,关联用户一起创建
DB.Create(&Article{
Title: "java",
User: User{
Name: "lin",
},
})
//创建文章,关联用户
var user User
DB.Take(&user, 2)
DB.Create(&Article{
Title: "C++",
User: user,
})
//创建文章,关联用户
a1 := Article{Title: "golang零基础入门", UserID: 1}
DB.Create(&a1)
//外键添加
//给现有用户绑定文章
var user User
DB.Take(&user, 2)
var article Article
DB.Take(&article, 5)
//使用append
DB.Model(&user).Association("Articles").Append(&article)
//其他方法
//user.Articles = []Article{article}
//DB.Save(&user)
//给现有文章关联用户
var article Article
DB.Take(&article, 5)
article.UserID = 1
DB.Save(&article)
//使用append
var article Article
DB.Take(&article, 5)
DB.Model(&article).Association("User").Append(&user)
查询
预加载
//显示文章列表
var user User
DB.Preload("Articles").Take(&user, 1)
fmt.Println(user)
//查询文章,显示文章的用户信息
var article Article
DB.Preload("User").Take(&article, 1)
fmt.Println(article)
嵌套预加载
var article Article
DB.Preload("User.Articles").Take(&article, 1)
fmt.Println(article)
带条件的预加载
查询用户下的所有文章列表,过滤某些文章
var user User
DB.Preload("Articles", "id = ?", 1).Take(&user, 1)
fmt.Println(user)
这样,就只有id为1的文章被预加载出来了
自定义预加载
var user User
DB.Preload("Articles", func(db *gorm.DB) *gorm.DB {
return db.Where("id in ?", []int{1, 2})
}).Take(&user, 1)
fmt.Println(user)
删除
级联删除
删除用户,与用户关联的文章也会删除
var user User
DB.Take(&user, 1)
DB.Select("Articles").Delete(&user)
清除外键关系
删除用户,与将与用户关联的文章,外键设置为null
var user User
DB.Preload("Articles").Take(&user, 2)
DB.Model(&user).Association("Articles").Delete(&user.Articles)
一对一关系
//添加用户,会自动添加用户详情
DB.Create(&User{
Name: "lin",
Age: 18,
Gender: true,
UserInfo: UserInfo{
Addr: "河南",
Like: "sleep",
},
})
//查询
var user User
DB.Preload("UserInfo").Take(&user)
fmt.Println(user)
多对多关系
添加
//添加文章,并创建标签
DB.Create(&Article{
Title: "《python》",
Tags: []Tag{
{Name: "python"},
{Name: "编程"},
},
})
//添加文章,选择标签
var tags []Tag
DB.Find(&tags, "name = ?", "编程基础")
DB.Create(&Article{
Title: "《golang》",
Tags: tags,
})
查询
//查询文章,显示文章标签列表
var article Article
DB.Preload("Tags").Take(&article, 1)
fmt.Println(article)
//查询标签显示文章列表
var tag Tag
DB.Preload("Articles").Take(&tag, 2)
fmt.Println(tag)
多对多更新
//更新
//移除文章标签
var article Article
DB.Preload("Tags").Take(&article, 1)
DB.Model(&article).Association("Tags").Delete(article.Tags)
fmt.Println(article)
//更新文章标签
var article Article
var tags []Tag
DB.Find(&tags, []int{1})
DB.Preload("Tags").Take(&article, 2)
DB.Model(&article).Association("Tags").Replace(tags)
fmt.Println(article)
自定义连接表
DB.Debug().Migrator().DropTable(ArticleTag{})
//自定义连接表
//显示除了双方的主键id的其他列
//生成表结构
//设置Article的Tags表为ArticleTag
DB.SetupJoinTable(&Article{}, "Tags", &ArticleTag{})
//如果tag要反向应用article,那么也要加上
DB.SetupJoinTable(&Tag{}, "Articles", &ArticleTag{})
err := DB.AutoMigrate(&Article{}, &Tag{}, &ArticleTag{})
fmt.Println(err)
//添加文章标签,并自动关联
DB.SetupJoinTable(&Article{},"Tags",&ArticleTag{})//必须先设置这个才能走到自定义连接表
DB.Create(&Article{
Title: "《gorm入门》",
Tags: []Tag{
{Name: "go"},
{Name: "web"},
{Name: "后端"},
},
})
//添加文章,关联已有标签
DB.SetupJoinTable(&Article{},"Tags",&ArticleTag{})//必须先设置这个才能走到自定义连接表
DB.SetupJoinTable(&Article{}, "Tags", &ArticleTag{})
var tags []Tag
DB.Find(&tags, "name is ?", []string{"web", "后端"})
DB.Create(&Article{
Title: "《gin框架入门》",
Tags: tags,
})
//给已有文章关联标签
DB.SetupJoinTable(&Article{}, "Tags", &ArticleTag{})
article := Article{
Title: "《django基础》",
}
DB.Create(&article)
var at Article
var tags []Tag
DB.Find(&tags, "name in ?", []string{"go", "web"})
DB.Take(&at, article.ID).Association("Tags").Append(tags)
//替换已有文章的标签
DB.Model(&article).Association("Tags").Replace(tags)
//查询文章列表,显示标签
DB.Preload("Tags").Find(&article)
fmt.Println(article)
自定义连接表主键
type ArticleModel struct {
ID uint
Title string
Tags []TagModel `gorm:"many2many:article_tags;joinForeignKey:ArticleID;JoinReferences:TagID"`
}
type TagModel struct {
ID uint
Name string
Articles []ArticleModel `gorm:"many2many:article_tags;joinForeignKey:TagID;JoinReferences:ArticleID"`
}
type ArticleTagModel struct {
ArticleID uint `gorm:"primaryKey"` // article_id
TagID uint `gorm:"primaryKey"` // tag_id
CreatedAt time.Time
}
func main(){
DB.SetupJoinTable(&ArticleModel{}, "Tags", &ArticleTagModel{})
DB.SetupJoinTable(&TagModel{}, "Articles", &ArticleTagModel{})
err := DB.AutoMigrate(&ArticleModel{}, &TagModel{}, &ArticleTagModel{})
fmt.Println(err)
}