package _case
import "gorm.io/gorm"
func init() {
DB.Migrator().AutoMigrate(Teacher{}, Course{})
}
type Roles []string
type Teacher struct {
gorm.Model
Name string `gorm:"size:256"`
Email string `gorm:"size:256"`
Salary float64 `gorm:"scale:2;precision:7"` // 指定小数部分宽度为2,列宽度为7. 列宽:【整数部分+小数部分的总长度】【不含小数点】
Age uint8 `gorm:"check:age>30"`
Birthday int64 `gorm:"serializer:unixtime;type:time"` // 反序列化方式 unixtime, 类型为time
Roles Roles `gorm:"serializer:json"`
JobInfo Job `gorm:"embedded;embeddedPrefix:job_"` // 嵌套字段, 嵌入字段的列名前缀job_
JobInfo2 Job `gorm:"type:bytes;serializer:gob"` // 字节流类型,gob反序列化,go自己的序列化方法,跨语言项目的时候,不建议用
}
type Job struct {
Title string
Location string
}
type Course struct {
gorm.Model
Name string `gorm:"size:256"`
Price float64 `gorm:"scale:2;precision:7"`
UserID uint `gorm:"type:int"`
}
package _case
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"time"
)
var DB *gorm.DB
var dsn = "root:123456@tcp(10.74.18.61:3306)/mydb?charset=utf8mb4&parseTime=True&loc=Local"
func init() {
var err error
// 每次调用返回的都是DB对象,这是支持链式调用的
DB, err = gorm.Open(mysql.New(mysql.Config{
DSN: dsn,
DefaultStringSize: 256,
}), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
//开启预编译,提高后续调用速度
//开启预编译的情况下,不支持嵌套事务
PrepareStmt: true,
})
if err != nil {
log.Println(err)
return
}
setPool(DB)
}
// 连接池设置
func setPool(db *gorm.DB) {
sqlDB, err := db.DB()
if err != nil {
log.Println(err)
return
}
// 连接存活最大时长
sqlDB.SetConnMaxLifetime(time.Hour)
// 最大空闲连接数
sqlDB.SetMaxIdleConns(5)
// 最大连接打开数
sqlDB.SetMaxOpenConns(10)
}
假数据定义
var teacherTemp = Teacher{
Name: "kk",
Age: 40,
Salary: 1234.22,
Email: "[email protected]",
Birthday: time.Now().Unix(),
Roles: Roles{"普通用户", "讲师"},
JobInfo: Job{
Title: "教授",
Location: "九龙湖",
},
JobInfo2: Job{
Title: "教授",
Location: "九龙湖",
},
}
t1 := teacherTemp
res := DB.Create(&t) // 指针传入
t1 := teacherTemp
res = DB.Select("name", "age").Create(&t1)
t2 := teacherTemp
res = DB.Omit("email", "Birthday").Create(&t2)
var teachers = []Teacher{{Name: "qq", Age: 50}, {Name: "pp", Age: 60}, {Name: "gg", Age: 55}, {Name: "mm", Age: 56}}
DB.CreateInBatches(teachers, len(teachers)) // 或者直接DB.Create(teachers)
t3 := teacherTemp
t3.Name = "oo"
out := Teacher{}
res = DB.Attrs(t3).FirstOrCreate(&out, Teacher{Name: "oo"})
gorm采用的是软删除,删除语句为update,去更新delete_at字段
DB.Delete(&Teacher{Model: gorm.Model{ID: 9}})
gorm输出语句(软删除)
UPDATE `teachers` SET `deleted_at`='2023-10-09 18:51:43.901' WHERE `teachers`.`id` = 9 AND `teachers`.`deleted_at` IS NULL
DB.Where("name like ?", "yuan*").Delete(&Teacher{})
DB.Delete(&Teacher{}, []int{3,4,5,})
DB.Delete(&Teacher{}, 1)
DB.Delete(&Teacher{}, []int{3,4,5,})
teacher := Teacher{}
DB.First(&teacher)
// 更新
teacher.Age = 66
teacher.Name = "wang"
// 更新所有 save 会将所有字段保存到数据库, 无论字段有没有被改
DB.Save(teacher)
DB.Model(&Teacher{}).Where("id = ?", teacher.ID).Update("name", "yuan")
DB.Model(&Teacher{Model:gorm.Model{ID: teacher.ID}}).Update("name", "yuan")
// 更新单行多个列 结构体方式
DB.Model(&Teacher{}).Where("id = ?", teacher.ID).Updates(Teacher{Name: "updatayuan", Age: 40})
// 更新单行多个列 map方式
DB.Model(&Teacher{}).Where("id = ?", teacher.ID).Updates(map[string]interface{}{"name": "updateY", "age": 40})
DB.Model(&Teacher{}).Where("age > ?", 60).Updates(Teacher{Email: "[email protected]"}) // 用map也行
// 选定更新某些字段
DB.Model(&Teacher{}).Where("id = ?", 5).Select("name", "age").Updates(teacher)
// 排除某些字段 更新
DB.Model(&Teacher{}).Where("id = ?", 5).Omit("name", "age").Updates(teacher)
func GetOnce() {
t := Teacher{}
// 查询一条
// 获取主键排序第一条
DB.First(&t)
// 无排序规则 取第一条
t = Teacher{}
DB.Take(&t)
// 主键排序最后一条
t = Teacher{}
DB.Last(&t)
//查询结果填充到集合中
result := map[string]interface{}{}
// 可能会有特殊类型不好处理,无法完成类型转换,可以忽略一些字段
DB.Model(&Teacher{}).Omit("Birthday", "Roles", "JobInfo2").First(&result)
// 基于表名 查询记录
result = map[string]interface{}{}
DB.Table("teachers").Take(&result)
}
func GetByStrCond() {
t := Teacher{}
var teaches []Teacher
DB.Find(&teaches, "name IN ?", []string{"yuan", "oo", "gg"})
DB.Where("name = ?", "gg").First(&t)
DB.Where("name IN ?", []string{"yuan", "oo"}).Find(&teaches)
}
func GetByStructOrMapCond() {
var teachers []Teacher
t := Teacher{}
//struct
DB.Find(&teachers, Teacher{Name: "oo", Age: 40})
// map
DB.Find(&teachers, map[string]interface{}{"Name": "gg", "Age": 40})
DB.Where(Teacher{Name: "yuan", Age: 40}).First(&t)
DB.Where(map[string]interface{}{"Name": "qq", "Age": 40}).Find(&teachers)
DB.Where([]int{10, 11, 12}).Find(&teachers)
//指定查询条件使用的字段
DB.Where(Teacher{Name: "cc"}, "name", "age").Find(&teachers)
}
var teachers []Teacher
// 复合查询 offset为跳过几个记录,分页会用
DB.Where(DB.Where("name = ?", "yuan").Or("name = ?", "oo")).
Where("age > ?", 40).Order("id desc").Offset(1).Limit(10).Find(&teachers)
// 查询返回行rows
rows, err := DB.Model(&Teacher{}).Select("id", "name").Where(DB.Where("name in ?", []string{"oo", "qq"})).
Order("id desc").Offset(1).Limit(10).Rows()
if err != nil {
log.Fatal(err)
}
defer rows.Close()
// 扫描row
for rows.Next() {
id := 0
name := ""
err = rows.Scan(&id, &name)
if err != nil {
continue
}
fmt.Println(id, name)
}
// 分组聚合
type Result struct {
Count int
Age int
}
list := []Result{}
DB.Model(&Teacher{}).Select("count(*) as count", "age").Not("name = ?", "yuan").
Group("age").Having("count > ?", 2).Rows()
fmt.Println(list)
// 根据年龄分组,过滤掉name为yuan的数据,保留对应分组count数大于2的结果
rows2, err := DB.Model(&Teacher{}).Select("count(*) as count", "age").Not("name = ?", "yuan").
Group("age").Having("count > ?", 2).Rows()
if err != nil {
log.Fatal(err)
}
defer rows2.Close()
for rows2.Next() {
count := 0
age := 0
err = rows2.Scan(&count, &age)
if err != nil {
continue
}
fmt.Println(count, age)
}
基本exec和raw就够用了
func NativeSql() {
var teacher Teacher
var list []Teacher
//查询
DB.Raw("select id,name,age from teachers where name = ?", "yuan").Scan(&teacher)
fmt.Println(teacher)
DB.Raw("select id,name,age from teachers where name = ?", "yuan").Scan(&list)
fmt.Println(list)
teacher = Teacher{}
DB.Raw("select id,name,age from teachers where name = ?", "yuan").Find(&teacher)
fmt.Println(teacher)
//更新
res := DB.Exec("update teachers set age = @age where name = @name", sql.Named("age", 22), sql.Named("name", "yuan"))
fmt.Println(res.RowsAffected, res.Error)
}