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、最后,各位小伙伴,麻烦给老哥一个点赞、关注、收藏三连好吗,你的支持是老哥更新最大的动力,谢谢!