gorm
用 go mod 管理模块
-
导包
import ( "time" "gorm.io/driver/mysql" gorm "gorm.io/gorm" )
-
创建数据库引擎
db, err := gorm.Open(mysql.Open(MYSQL_URL)) if err != nil { fmt.Println(err) }
-
定义模型结构体
// column 字段名 // type 字段类型 bool、int、uint、float、string、time、bytes // scale ,size 字段长度 size貌似不起作用 // default 默认值 // primaryKey 主键 // index ,uniqueIndex 索引,唯一索引 // unique 唯一约束 // not null 非空约束 // check 检查 // autoIncrement 自增长 autoIncrementIncrement 自增长的步长 // embedded 嵌套 embeddedPrefix 嵌套前缀 // autoCreateTime 自动生成创建时间如果增操作没有传值 // autoUpdateTime 自动生成更新时间如果更新操作没有传值 // comment 备注信息 type Class struct { ID uint64 `gorm:"Primarykey;autoIncrement"` Name string `gorm:"column:my_name;Type:string;scale:100"` CreatedAt time.Time // CreatedAt 会在创建时如果是空会自动创建当前时间 UpdatedAt time.Time `gorm:"autoCreateTime;autoUpdateTime"` // 更新也一样 Flag bool `gorm:"type:bool;default:1"` // bool在数据库是0或1 } type Student struct { gorm.Model // 嵌套gorm定义的基类 Name string Age uint8 C_id uint64 } // gorm提供了四种验证钩子函数 func (s *Student) BeforeCreate(tx *gorm.DB) error { if s.Age <= 18 { return errors.New("Student.BeforeCreate") } return nil }
-
设置自动迁移
db.AutoMigrate(&Class{}) db.AutoMigrate(&Student{})
-
增
// 相当于修改了结构体,数据库中会自动更新 c1 := &Class{ Name: "一年级一班", } db.Create(c1) db.Create(&Class{ Name: "一年级二班", }) // 指定字段新增 指定的字段是结构体重的字段,不是数据库的 db.Select("Name").Create(&Class{Name: "三年二班"}) // 忽略指定字段新增 忽略的字段就算是定义了也会忽略 db.Omit("ID").Create(&Class{Name: "三年三班", ID: 100}) // 批量插入 users := make([]Student, 100) for i := 0; i < 100; i++ { users[i] = Student{Name: fmt.Sprintf("user_%d", i)} } // db.Create(users) // 分批新增 10个一批,插入后commit db.CreateInBatches(users, 10) // 钩子函数验证 rst1 := db.Create(&Student{Name: "18岁的天空", Age: 17}) if rst1.Error != nil { // 如果校验不通过,会报错 fmt.Println(rst1.Error) }
-
删
// 主键删除 db.Delete(&Class{}, "1") // 条件删除 db.Where("id = ?", 100).Delete(&Student{}) // 删除指定的行 var cc = make([]Class, 0) db.Find(&cc, "id > ?", 300) fmt.Println(len(cc)) db.Delete(&cc)
-
改
// 修改符合条件的所有 db.Model(&Class{}).Where("id = ?", "2").Update("my_name", "一年级三班") // 修改查询到的某条记录 var ss Student db.Find(&ss, 1) ss.Name = "Lily" db.Save(&ss) // 条件更新 适用于多条记录时更新 db.Model(&ss).Where("id = ?", "2").Update("name", "取什么名字好呢") // 多字段更新 利用结构体 或者 map db.Model(&ss).Updates(Student{Name: "sssssss", Age: 22}) db.Model(&ss).Updates(map[string]interface{}{"name": "aaaaaaa", "age": 33})
-
查
// 单个 var s Student db.First(&s) // 主键排序返回第一个 fmt.Println(s) var s1 Student db.Last(&s1) // 主键倒序返回第一个 fmt.Println(s1) var s3 Student db.Take(&s3) // 任意一个结果 // 主键检索 var s4 Student db.First(&s4, 1) // 主键 = 1 fmt.Println(s4) var s5 Student db.First(&s5, "2") // 主键 = 2 字符串与整型一样的效果 fmt.Println(s5) var s6 Student db.Find(&s6, []int{1, 2, 3}) // 主键 in (1,2,3) fmt.Println(s6) // 检索全部 var c = make([]Class, 0) rst := db.Find(&c) fmt.Println(rst.RowsAffected) fmt.Println(c) fmt.Println(len(c)) // 条件检索 var c2 = make([]Class, 0) db.Where("my_name = ?", "一年级一班").Find(&c2) // 这里的条件是数据库中的字段条件 fmt.Println(c2) // like var c3 = make([]Class, 0) db.Where("my_name like ?", "一年级%").Find(&c3) fmt.Println(c3) fmt.Println(len(c3)) // between and var c4 = make([]Class, 0) db.Where("updated_at between ? and ?", time.Now().Add(-24*time.Hour), time.Now()).Find(&c4) fmt.Println(c4) fmt.Println(len(c4)) // 结构体多条件 var c5 = make([]Class, 0) db.Where(&Class{ID: 100}).Find(&c5) fmt.Println(c5) // map 多条件 var c6 = make([]Class, 0) db.Where(map[string]string{"my_name": "三年二班"}).Find(&c6) // map 中的字段也是数据库中的字段 fmt.Println(c6) // Find 字符串查询 var c7 = make([]Class, 0) db.Find(&c7, "my_name", "三年二班") fmt.Println(c7) var c8 = make([]Class, 0) db.Find(&c8, &Class{Name: "一年级二班"}) fmt.Println(c8) // 取反 Not 和 Where相似 var c9 = make([]Class, 0) db.Not("my_name = ?", "三年二班").Find(&c9) fmt.Println(c9) // or var c10 = make([]Class, 0) db.Where("my_name = ?", "三年三班").Or("id < ?", 100).Order("id desc").Find(&c10) // order在最后没用 Find在最后才有用 fmt.Println(c10) // 查询指定字段 除了指定字段,其余的都是零值 var c11 = make([]Class, 0) db.Select("my_name", "id").Find(&c11, "id < ?", "10") fmt.Println(c11) // limit offset var c12 = make([]Class, 0) db.Offset(5).Limit(10).Find(&c12) fmt.Println(c12)
-
关联查询
rst2 := make([]map[string]interface{}, 0) rows2, _ := db.Table("students").Select("name,age,classes.my_name").Joins("left join classes on students.c_id=classes.id").Where("students.c_id is not null").Rows() for rows2.Next() { var ( name string age int class string ) rows2.Scan(&name, &age, &class) rst2 = append(rst2, map[string]interface{}{"name": name, "age": age, "class": class}) } fmt.Println(rst2)
-
分组聚合
type Result struct { Name string Cnt int } var r = make([]Result, 0) // 查询条件要是数据库内的字段,返回值的结构体字段要大写 db.Model(&Class{}).Select("my_name as name,count(id) as cnt").Group("name").Having("cnt > ?", 10).Find(&r) fmt.Println(r) // Rows 返回的是只有指定字段个数的通道 // 有点像数据库中的游标 rows, _ := db.Table("classes").Select("my_name as name,count(id) as cnt").Group("name").Having("cnt > ?", 10).Rows() for rows.Next() { var ( Name string Cnt int ) rows.Scan(&Name, &Cnt) fmt.Println(Name, Cnt) }
-
原生SQL执行
// 查询 var rst Result db.Raw("select my_name,count(*) as cnt from classes group by name").Scan(&rst) // 增删改 db.Exec("update classes set my_name = ? where id = ?","三年二班",1)
代码托管在gitee https://gitee.com/mslsy/golang_study/tree/master/19_other_packages/19_4_gorm
版权声明:本文为weixin_41546513原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。