Hello,各位小伙伴,大家好呀。老哥周六要加班,好累…,真的不想加班,但是没有办法,为了Money,只能忍一下。
老哥趁着下午摸鱼的时间,我们来学习一下Gorm
1、首先导入gorm包,参考文档,
https://learnku.com/docs/gorm/v2/index/9728
PS D:\Project\Go_Project\goproject1> go get -u gorm.io/gorm
PS D:\Project\Go_Project\goproject1> go get -u gorm.io/driver/sqlite
2、然后我们需要使用mysql,导入mysql的驱动包
D:\Project\Go_Project\goproject1> go get -u github.com/go-sql-driver/mysql
3、 gorm连接到Mysql数据库,使用Api,创建students表结构
补充: 里面有个创建表结构的方法,但是没有数据,老哥这里提供一下数据(当然你也可以自己造 dog狗头保命)
INSERT INTO
students
VALUES (1, ‘Jessica’, 25);
INSERT INTO
students
VALUES (2, ‘Jerry’, 26);
INSERT INTO
students
VALUES (3, ‘Tom’, 18);
INSERT INTO
students
VALUES (4, ‘lili’, 18);
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"log"
)
type Student struct {
Id int
Name string
Age int
}
func initGormDb() *gorm.DB {
dsn := "root:root@tcp(127.0.0.1:3306)/go-test?charset=utf8mb4&parseTime=True&loc=Local"
dbs, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//如果不想看到日志sql,这里可以关掉
Logger: logger.Default.LogMode(logger.Info),
})
if err != nil {
panic("gorm failed to connect Mysql...")
}
return dbs
}
// CreateTable 创建表
func CreateTable(db *gorm.DB) {
err := db.AutoMigrate(&Student{})
if err != nil {
log.Println("failed to create table...")
return
}
}
func main() {
db := initGormDb()
//1、创建表
CreateTable(db)
}
3A、插入数据,支持批量插入(CreateInBatches ),具体参考,
https://learnku.com/docs/gorm/v2/create/9732
//InsertData
func InsertData(db *gorm.DB) {
//插入一条
//p := Student{
// Name: "uzi",
// Age: 25,
//}
//tx := db.Create(&p)
//fmt.Println(tx.RowsAffected)
//插入多条
p2 := Student{
Name: "gala",
Age: 20,
}
p3 := Student{
Name: "wei",
Age: 19,
}
txs := db.Create(&[]Student{p2, p3})
fmt.Println(txs.RowsAffected)
}
5、查询数据,因为查询的话,没有固定的写法,老哥这里只是列举了常用的,详情参考,
https://learnku.com/docs/gorm/v2/advanced_query/9757
// SelectData 查询数据
/**
查询五花八门,我们可以按照需要进行定制查询
*/
func SelectData(db *gorm.DB) {
//1、保存多条数据
var stuList []Student
//2、保存单条数据
var stu Student
//按照主键查找
//db.First(&stu, 2)
//带条件查询,查一条
//db.First(&stu, "age=?", 18)
// 获取最后一条记录(主键降序)
//db.Last(&stu)
//获取全部数据
//db.Find(&stuList)
//where查询单条数据
//db.Where("age=?", 25).Find(&stu)
//db.Where(&Student{Age: 18}).Find(&stu)
//fmt.Println(stu)
//where查询多条数据
//db.Where("age=?", 18).Find(&stuList)
//where查询多条数据 or
//db.Where("age=? or age=?", 25, 26).Find(&stuList)
//db.Where("age=?", 18).Or("age=?", 26).Find(&stuList)
//fmt.Println(stuList)
//where查询通过单条数据 Map
db.Where(map[string]interface{}{"name": "uzi", "age": 25}).Find(&stu)
fmt.Println(stu)
//BETWEEN 查询年龄25到30
//db.Where("age BETWEEN ? AND ?", 25, 30).Find(&stuList)
//fmt.Println(stuList)
//order查询 按照年龄降序,默认是升序
//db.Order("age desc").Find(&stuList)
//fmt.Println(stuList)
//limit查询,查询前3条数据
//db.Limit(3).Find(&stuList)
//fmt.Println(stuList)
//Offset 跳过几条,查询前3条数据
//db.Limit(3).Offset(1).Find(&stuList)
//fmt.Println(stuList)
//Distinct 按照年龄去重,返回不重复的年龄
//db.Distinct("age").Find(&stuList)
//fmt.Println(stuList)
//Group分组 等同于 select age from students group by age
//db.Select("age").Group("age").Find(&stuList)
//fmt.Println(stuList)
//Having 查询年龄大于20
db.Having("age > ?", 20).Find(&stuList)
fmt.Println(stuList)
}
6、更新数据,参考资料,
https://learnku.com/docs/gorm/v2/update/9734
// UpdateStudentData 更新数据
func UpdateStudentData(db *gorm.DB) {
//单条更新 修改Jessica的年龄为18
//update := db.Model(Student{}).Where("name=?", "Jessica").Update("age", 18)
//fmt.Println(update.RowsAffected)
//批量更新 修改id为 6、7,年龄统一改为19
updates := db.Table("students").Where("id In ?", []int{6, 7}).Updates(map[string]interface{}{"age": 19})
fmt.Println(updates.RowsAffected)
}
7、删除数据,
注意这里增加了一个钩子,在删除之前,我们可以加一些属于自己的逻辑
//DeleteData 删除数据
func DeleteData(db *gorm.DB) {
//单条删除 删除id为7的数据
//deleteCount := db.Delete(&Student{}, "7")
//fmt.Println(deleteCount.RowsAffected)
//批量删除 删除id为5、6的数据
//deleteCountList := db.Delete(&Student{}, []int{5, 6})
//fmt.Println(deleteCountList.RowsAffected)
//删除钩子,因为删除一般是危险动作,我们可以考虑删除加个判断
//BeforeDelete 会在删除之前,自动调用
//下面的方法均不会触发钩子
//1.
//db.Delete(&User{}, 1)
2.
//db.Delete(&User{}, "id in ?", ids)
3.
//var ids = []uint{1,2,3}
//db.Where("id in ?",ids).Delete(&User{})
//钩子触发条件,stu里面必须有数据
//下面这种会触发钩子,单条删除
//var stu Student
//db.Where("id =3").Find(&stu).Delete(&stu)
//下面这种会触发钩子,多条删除
//var stuList []Student
//var ids = []uint{1, 2, 3}
//db.Where("id in ?", ids).Find(&stuList).Delete(&stuList)
//删除全部数据,不会触发钩子
db.Where("id > ?", 0).Delete(&Student{})
}
func (stu *Student) BeforeDelete(tx *gorm.DB) (err error) {
if stu.Name == "Jerry" {
fmt.Println("Jerry not allowed to delete")
return errors.New("Jerry not allowed to delete")
}
return
}
8、gorm基本的增删改查先介绍到这里,已经可以满足开发的日常需要。下面介绍一下,Gorm进阶
———————————————————————————————————————————————————————————->
9、gorm 支持我们写原生Sql,最大限度让我们自由发挥
//RawSql 支持原生sql
func RawSql(db *gorm.DB) {
var stuList []Student
// SELECT * FROM students WHERE name = "Jessica" OR name2 = "Tom"
db.Raw("SELECT * FROM students WHERE name = @name1 OR name = @name2",
sql.Named("name1", "Jessica"), sql.Named("name2", "Tom")).Find(&stuList)
fmt.Println(stuList)
// UPDATE students SET age = 20 where id in (2,3)"
//db.Exec("UPDATE students SET age = @ages where id in (2,3)",
// sql.Named("ages", 20))
}
10、一对多, 我们先创建表结构,然后插入数据
type Company struct {
ID uint `gorms:"primarykey"`
Name string
Workers []Worker //用来存放查询出来的所有打工人
}
type Worker struct {
ID uint `gorms:"primarykey"`
WorkerName string
CompanyID uint
}
func main() {
db := initGormDb()
//创建表,先有公司,然后有打工人
//db.AutoMigrate(&Company{}, &Worker{})
}
INSERT INTO
companies
VALUES (1, ‘jdg’);
INSERT INTO
workers
VALUES (‘yagao’, 1);
INSERT INTO
workers
VALUES (‘369’, 1);
INSERT INTO
workers
VALUES (‘kanavi’, 1);
INSERT INTO
workers
VALUES (‘hope’, 1);
INSERT INTO
workers
VALUES (‘missing’, 1);
package main
import (
"bytes"
"encoding/json"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
func initGormDb() *gorm.DB {
dsn := "root:root@tcp(127.0.0.1:3306)/go-test?charset=utf8mb4&parseTime=True&loc=Local"
dbs, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//如果不想看到日志sql,这里可以关掉
Logger: logger.Default.LogMode(logger.Info),
})
if err != nil {
panic("gorms failed to connect Mysql...")
}
return dbs
}
type Company struct {
ID uint `gorms:"primarykey"`
Name string
Workers []Worker //用来存放查询出来的所有打工人
}
type Worker struct {
ID uint `gorms:"primarykey"`
WorkerName string
CompanyID uint
}
func PrintJsonTree(obj interface{}) {
marshal, err := json.Marshal(obj)
//这里是把JSON格式,树形化输出,优雅地展示
var treeJSON bytes.Buffer
err = json.Indent(&treeJSON, marshal, "", "\t")
fmt.Println(string(treeJSON.Bytes()))
if err != nil {
panic(err)
}
}
func main() {
db := initGormDb()
//创建表,先有公司,然后有打工人
//db.AutoMigrate(&Company{}, &Worker{})
//1、一对多,一个公司有多名员工,插入数据
//w1 := Worker{
// ID: 8,
// WorkerName: "knight",
//}
//
//w2 := Worker{
// ID: 9,
// WorkerName: "tian",
//}
//
//c := Company{
// ID: 3,
// Name: "tes",
// Workers: []Worker{w1, w2},
//}
//
//db.Create(&c)
//2、一对多,一个公司有多名员工,查询数据
//查询公司为jdg的信息
var company Company
//注意:Workers取得是 Workers []Worker 的变量,Preload预加载
//它会先 SELECT * FROM `workers` WHERE `workers`.`company_id` = 1
//然后 SELECT * FROM `companies` WHERE `companies`.`id` = '1'
db.Preload("Workers").Find(&company, "1")
//Preload 还可以增加你想要的条件,比如,我只带369出来
//Worker_Name 对应数据库的 Worker_Name
//db.Preload("Workers", "Worker_Name=?", "369").Find(&company, "1")
PrintJsonTree(company)
}
一对多,打印结果如下:
11、多对一
//多对一查询
//多个打工人,对应一个公司,查询数据
var WorkList []Worker
//查询所有在jdg的员工信息,多对一
db.Where("company_id =? ", 1).Find(&WorkList)
PrintJsonTree(WorkList)
多对一,查询结果如下:
12、多对多,
注意:多对多插入数据要分两次插入,因为中间表的插入,第二次不能再新增ID
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
func initGormDb() *gorm.DB {
dsn := "root:root@tcp(127.0.0.1:3306)/go-test?charset=utf8mb4&parseTime=True&loc=Local"
dbs, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//如果不想看到日志sql,这里可以关掉
Logger: logger.Default.LogMode(logger.Info),
})
if err != nil {
panic("gorms failed to connect Mysql...")
}
return dbs
}
// User 拥有并属于多种 language,`user_languages` 是连接表
type User struct {
gorm.Model
UserName string
Languages []Language `gorm:"many2many:user_languages;"` //加了这个,需要绑定另外一个many2many,然后会创建一张中间表
}
type Language struct {
gorm.Model
Name string
Users []User `gorm:"many2many:user_languages;"` //加了这个,需要绑定另外一个many2many,然后会创建一张中间表
}
//多对多
func main() {
db := initGormDb()
db.AutoMigrate(&User{}, &Language{}) //第一次插入需要
u1 := User{
UserName: "大佬1号",
}
u2 := User{
UserName: "大佬2号",
}
l1 := Language{
Name: "English",
Users: []User{u1, u2},
}
//
第一次插入数据,英语有两个大佬学
db.Create(&l1)
}
第二次插入数据,
u1 u2 l2三处调整
//多对多
func main() {
db := initGormDb()
//db.AutoMigrate(&User{}, &Language{})
u1 := User{
Model:gorm.Model{
ID: 1,
},
UserName: "大佬1号",
}
u2 := User{
Model:gorm.Model{
ID: 2,
},
UserName: "大佬2号",
}
//l1 := Language{
// Name: "English",
// Users: []User{u1, u2},
//}
l2 := Language{
Name: "Math",
Users: []User{u1, u2},
}
//
第一次插入数据,英语有两个大佬学
//db.Create(&l1)
//第二次插入,数学有两个大佬学
db.Create(&l2)
}
如果是正常插入,中间表 user_languages 的显示如下:
13、然后多对多,打印输出
func PrintJsonTrees(obj interface{}) {
marshal, err := json.Marshal(obj)
//这里是把JSON格式,树形化输出,优雅地展示
var treeJSON bytes.Buffer
err = json.Indent(&treeJSON, marshal, "", "\t")
fmt.Println(string(treeJSON.Bytes()))
if err != nil {
panic(err)
}
}
//多对多
func main() {
db := initGormDb()
//多对多查询
var UserList []User
db.Preload("Languages").Find(&UserList)
PrintJsonTrees(UserList)
}
多对多,结果查询如下:
14、最后,各位小伙伴,麻烦给老哥一个点赞、关注、收藏三连好吗,你的支持是老哥更新最大的动力,谢谢!