主頁 > 資料庫 > Golang的ORM框架之gorm

Golang的ORM框架之gorm

2020-12-25 08:01:21 資料庫

前言

ORM全稱Object Relational Mapping,是把編程語言中的Object/Struct資料型別映射到關系資料庫中1張表,以下是詳細映射關系,

結構體------------     資料表

結構體實體----------    表中1條記錄

結構體欄位------------  結構體欄位

 

gorm簡介

面向github編程找一找Golang中比較流行的orm,

注意Django的orm是包含在Django web框架中的,而gorm有點像Python中的sqlalchemy它不限制你必須要在某個web框架中使用它,

gorm中文官方網站內含十分齊全的中文檔案,

 

本文將圍繞當前最近版本gorm v1.20.8展開,

go.mod

module golang-gorm

go 1.14

require (
    github.com/go-sql-driver/mysql v1.5.0
    gorm.io/driver/mysql v1.0.3
    gorm.io/gorm v1.20.8
)

 

gorm安裝

SET GOPROXY=https://goproxy.cn 
go get -u github.com/jinzhu/gorm

 

連接資料庫

在golang中連接不同的資料就需要使用不同的driver驅動,

GORM 官方支持的資料庫型別有: MySQL, PostgreSQL, SQlite, SQL Server

"gorm.io/driver/mysql" //MySQL驅動

"gorm.io/driver/sqlite"//sqllite的驅動

"gorm.io/driver/postgres" //postgres的驅動

開始

package main

import (
	"fmt"
	"gorm.io/driver/mysql" //MySQL驅動
	"gorm.io/gorm"
	"time"
)

func init() {
	//配置資料連接:注意設定parseTime=true否則會報錯!unsupported Scan 時間型別的欄位
	dbinfo := "zhanggen:xxoo@tcp(192.168.56.18:3306)/web?charset=utf8&parseTime=true&loc=Local"
	db, err := gorm.Open(mysql.Open(dbinfo), &gorm.Config{})
	//配置一下資料連接引數!
	mySQL, err := db.DB()
	if err != nil {
		fmt.Println(err)
	}
	defer mySQL.Close()
	//設定最大空閑連接
	mySQL.SetMaxIdleConns(10)
	//設定最大連接數
	mySQL.SetMaxOpenConns(100)
	//設定連接超時時間:1分鐘
	mySQL.SetConnMaxLifetime(time.Minute)

}

  

Model定義

我們在創建Table的時可以通過設定struct欄位的tag,對數 表名、欄位進行屬性設定,

結構體

package book

import "time"

type Book struct {
	ID          uint       `gorm:"column:id;primaryKey"`
	Title       string     `gorm:"column:title;not null;type:varchar(100);unique_index"` //指定資料庫列的資料型別
	Author      string     `gorm:"column:author;not null;size:125"`             //設定Author在資料庫中不能為空,欄位大小為255
	Publishtime *time.Time `gorm:"column:publishtime"`
}
// 將默認表面Book 的表名設定為book
func (Book) TableName() string {
	return "book"
}

--------------------------------

package login

//用戶表
type UserInfo struct {
	ID       uint   `gorm:"column:id;primaryKey"`
	Username string `gorm:"column:username;unique;not null;index"`
	Password string `gorm:"column:password;not null;"`
}

// 將 UserInfos 的表名設定為 `user`
func (UserInfo) TableName() string {
	return "user"
}

  

Mysql

MariaDB [web]> desc book;
+-------------+---------------------+------+-----+---------+----------------+
| Field       | Type                | Null | Key | Default | Extra          |
+-------------+---------------------+------+-----+---------+----------------+
| id          | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| title       | varchar(100)        | NO   |     | NULL    |                |
| author      | varchar(125)        | NO   |     | NULL    |                |
| publishtime | datetime(3)         | YES  |     | NULL    |                |
+-------------+---------------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

-------------------------------------

MariaDB [web]> desc user;
+----------+---------------------+------+-----+---------+----------------+
| Field    | Type                | Null | Key | Default | Extra          |
+----------+---------------------+------+-----+---------+----------------+
| id       | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| username | varchar(191)        | NO   | UNI | NULL    |                |
| password | longtext            | NO   |     | NULL    |                |
+----------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

 

Django orm的差別

當我們Django的model中修改了表欄位需要先make magrations生成操作,然后再make magirate去資料庫真正執行這次magration,保證了資料庫的安全,

而gorm只要你執行db.AutoMigrate()就會實時修改表結構,但是當你使用Django orm 修改了資料庫欄位magration時經常報錯Exist table讓你不知所措,

 

查看gorm操作日志 

db.Debug可以幫助我們顯示gorm對資料庫的操作

db.Debug().AutoMigrate(&User{})

日志內容

[1.000ms] [rows:0] ALTER TABLE `users` MODIFY COLUMN `age` bigint DEFAULT 19

 

增刪改查CURD

立即執行方法(Immediate Methods):查詢只有執行了立即執行函式才會去資料庫查詢 First/Find/FirstrOrInit/FirstOrCreate/

行內條件 inline condition:就是把SQL查詢條件當做引數傳遞到立即執行函式中執行,

gorm支持使用String、Struct&Map作為條件進行查詢已經鏈樣操作,

 

創建單條記錄

  /1.創建單條記錄
    u := User{Name: "Martin", Age: 19}
    result := Model.Create(&u)
    //回傳插入資料的主鍵
    fmt.Println(u.ID)
    //回傳的error
    fmt.Println(result.Error)
    //回傳插入記錄的條數
    fmt.Println(result.RowsAffected)
    //如果記錄存在將不再重復創建
    result = Model.FirstOrCreate(&u)
    if result.RowsAffected == 0 {
        fmt.Println("記錄已經存在!")
    }

 

批量創建

在生產環境之中如果你插入資料特別頻繁,可以使用批量插入的方式進行優化,如果資料沒有實時展示的要求,

    //批量創建
    var userList = []User{{Name: "jinzhu1"}, {Name: "jinzhu2"}, {Name: "jinzhu3"}}
    Model.Debug().Create(&userList)
    for _, user := range userList {
        fmt.Println(user.ID) // 1,2,3
    }

 

 

 查詢

new和make區別:make給map/channel/slince申請記憶體和容量回傳值型別,new初始化基本型別string/int/結構體回傳指標型別的變數

 

主鍵查詢

Objects can be retrieved using primary key by using Inline Conditions.

Be extra careful with strings to avoid SQL Injection, check out Security section for details 

通過行內條件的方式,我們可以根據主鍵獲取到資料庫中的1/多條記錄,

db.First(&user, 10)
// SELECT * FROM users WHERE id = 10;

db.First(&user, "10")
// SELECT * FROM users WHERE id = 10;

db.Find(&users, []int{1,2,3})
// SELECT * FROM users WHERE id IN (1,2,3);

 

一般查詢

    //1.普通查詢
    u := new(User)
    //查詢第1條資料
    Model.Debug().First(u) //SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1
    fmt.Println(u.Name)
    Model.Debug().First(u, 10)
    fmt.Println(u)
    //隨機獲取1條記錄
    u = new(User)         //new和make區別:make給map/channel/slince申請記憶體和容量回傳值型別,new初始化基本型別string/int/結構體回傳指標型別的變數
    Model.Debug().Take(u) //SELECT * FROM `users` LIMIT 1
    fmt.Println(u.Name)
    //獲取最后1條記錄
    u = new(User)
    Model.Last(u)
    fmt.Println(u.Name)
    //查詢表中所有記錄
    userList := []User{} //SELECT * FROM `users`
    Model.Debug().Find(&userList)
    fmt.Println(userList)

 

Where 條件查詢

    //查詢所有匹配的記錄 然后獲取第1條
    u=new(User)
    Model.Debug().Where("name=?","jinzhu1").First(&u)//SELECT * FROM `users` WHERE name='jinzhu1' ORDER BY `users`.`id` LIMIT 1
    fmt.Println(u.Name)
    //查詢所有匹配的記錄,獲取所有
    userList=[]User{}
    Model.Debug().Where("name=?","Martin").Find(&userList)  //SELECT * FROM `users` WHERE name='Martin'
    fmt.Println(userList)

    userList=[]User{}
    Model.Debug().Where("name <>?","Martin").Find(&userList) //SELECT * FROM `users` WHERE name <>'Martin'
    fmt.Println(userList)

    userList=[]User{}
    Model.Debug().Where("name in?",[]string{"jinzhu"}).Find(&userList) //SELECT * FROM `users` WHERE name in('jinzhu')
    fmt.Println(userList)

 

使用Struct & Map & 切片進行查詢

我們可使用結構體、map、slice把搜索條件組合起來,

    //struct
    u = new(User)
    Model.Debug().Where(User{Name: "曹操", Age: 29}).First(&u)
    fmt.Println(u.Name)
    userList=[]User{}
    //map:我們可以使用map接收前端的json然后做組合搜索
    Model.Debug().Where(map[string]interface{}{"name": "希拉里", "age": 29}).Find(&userList) //SELECT * FROM `users` WHERE `users`.`name` = '曹操' AND `users`.`age` = 29 ORDER BY `users`.`id` LIMIT 1
    fmt.Println(userList)
    //主鍵的切片
    userList=[]User{}
    Model.Where([]int64{1,2,4,6}).Find(&userList)
    fmt.Println(userList)

 

 

Not 條件查詢

我們可以使用Where指定篩選條件,也可以使用Not排除一些條件,

    //not條件查詢
    u = new(User)
    userList = []User{}
    //1.不等于 <>
    //SELECT * FROM `users` WHERE `name` <> 'jinzhu' ORDER BY `users`.`id`
    Model.Debug().Not("name", "jinzhu").First(&u)
    fmt.Println(u.Name)
    //SELECT * FROM `users` WHERE `name` <> 'Martin'
    Model.Debug().Not("name", "Martin").Find(&userList)
    fmt.Println(userList)
    //2.不在x范圍之類 Not In
    userList = []User{}
    //SELECT * FROM `users` WHERE `users`.`id` NOT IN (1,4)
    Model.Debug().Not([]int64{1, 4}).Find(&userList)
    fmt.Println(userList)
    //SELECT * FROM `users`
    userList = []User{}
    Model.Debug().Not([]int64{}).Find(&userList)
    fmt.Println(userList)
    //4.執行原生Sql
    userList = []User{}
    Model.Debug().Not("name=? or age<10", "Martin").Find(&userList)
    fmt.Println(userList)
    //5.not和where一樣同樣支持 通過struct/map/切片來組裝搜索條件
    userList = []User{}
    Model.Debug().Not(User{Name: "Martin", Age: 19}).Find(&userList)
    fmt.Println(userList)

    userList = []User{} //SELECT * FROM `users` WHERE (`age` <> 19 AND `name` <> 'jinzhu')
    Model.Debug().Not(map[string]interface{}{"name": "jinzhu", "age": 19}).Find(&userList)
    fmt.Println(userList)

    userList = []User{}
    Model.Debug().Not([]int64{1, 2}).Find(&userList) //SELECT * FROM `users` WHERE `users`.`id` NOT IN (1,2)
    fmt.Println(userList)

 

 

Or條件查詢

我可以使用Or連接2個搜索條件,

//Or條件
    userList = []User{}
    Model.Where("name=?", "Martin").Or("name=?", "jinzhu").Find(&userList)
    fmt.Println(userList)
    //Or也支持Struct、map、slice進行條件組成搜索
    userList = []User{}
    //SELECT * FROM `users` WHERE `users`.`name` = 'Martin' AND `users`.`age` = 29 OR (`users`.`name` = 'jinzhu' AND `users`.`age` = 29)
    Model.Debug().Where(User{Name: "Martin", Age: 29}).Or(User{Name: "jinzhu", Age: 29}).Find(&userList)
    fmt.Println(userList)
    //SELECT * FROM `users` WHERE `users`.`id` IN (1,2) OR `users`.`id` IN (5,4)
    Model.Debug().Where([]int64{1, 2}).Or([]int64{5,4}).Find(&userList)
    fmt.Println(userList)

 

行內條件查詢

通過以上大量的實驗你會發現我總會在Where/Not/Or里面組織搜索條件,然后再 .First/Find,

這是Where/Not/Or中的SQL需要借助立即執行方法 才真正把SQL發送到mysqld(服務端)執行,然后回傳值,我們宣告的變數才會獲取到值,

 

您會發現.Find()和.First()t這些立即執行方法可以接收2個引數(dest interface{}, conds ...interface{})

第1個引數用于接收和保存服務端(mysqld)回傳的結果、第2個用于客戶端(MySQL)輸入SQL搜索條件,

什么是行內條件查詢呢?

就是我們在把接收查詢結果的變數、SQL查詢條件傳遞到.Find()/.First()/.Not()/.Or()這些立即執行函式中執行就屬于行內條件查詢,

//行內條件
    //1.根據主鍵獲取記錄 (只適用于整形主鍵)
    u1 := new(User)
    Model.Debug().First(&u1, 1)
    fmt.Println(u1.Age)
    u1 = new(User)
    Model.Debug().First(&u1, "id = ?", 1)
    fmt.Println(u1.Name)
    //2.根據搜索條件獲取多條資料
    users := []User{}
    Model.Debug().Find(&users, "name = ?", "jinzhu")
    fmt.Println(users)
    //3.使用結構體作為搜索引數
    users = []User{}
    Model.Debug().Find(&users, User{Age: 29})
    fmt.Println(users)
    //4.使用map組織搜索條件
    users = []User{}
    Model.Debug().Find(&users, map[string]interface{}{"age": "29"})
    fmt.Println(users)
    //5.使用slice作為搜索條件
    users=[]User{}
    Model.Debug().Find(&users,[]int64{1,6})
    fmt.Println(users)

 

設定查詢選項

GORM 提供了 SetGetInstanceSetInstanceGet 方法來允許用戶傳值給 勾子 或其他方法

Gorm 中有一些特性用到了這種機制,如遷移表格時傳遞表格選項,

    err = db.Debug().Set("gorm:table_options","ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1").AutoMigrate(&User{})
    if err != nil {
        fmt.Println("創建表失敗",err)
    }
    fmt.Println("---------------------","創建表成功")

 

我們在查詢 SQL是可以設定添加1個行鎖(在我查詢這條記錄的時候別人就無法修改這條資料了)

users=[]User{}
Model.Debug().Set("gorm:query_option","FOR UPDATE").Find(&users,[]int64{1,5})
fmt.Println("--------",users)
u1=new(User)
Model.Set("gorm:query_option","FOR UPDATE").Debug().First(&u1,10)
fmt.Println(u1.Name)

  

FirstOrInit查詢

gorm的核心功能就是把資料庫回傳的1條記錄轉換成golang中的結構體并對欄位進行賦值,

如果在某些情況下我的SQL查詢沒有回傳任何記錄,那我的stuct變數的全部欄位就會使用零值

可以使用 Attrs和Assign方法對 FirstOrInit回傳的空記錄 進行struct欄位進行賦值,

attrs:獲取匹配的第1條記錄,否則根據給定的條件初始化一個新的物件 (僅支持 struct 和 map 條件)

Assign:不管記錄是否找到,都將引數賦值給 struct變數,

  //FirstOrint
    //如果找到了就把資料庫回傳的結果賦值給u2,如果沒有找到也不要緊把查詢條件賦值給u2進行初始化,
    u2:=new(User)
    Model.FirstOrInit(u2,User{Name: "Martin"})
    fmt.Println(u2.Name)
    //在資料庫沒有回傳查詢結果的情況下:使用Attrs指定Init時欄位的值
    u2=new(User)
    Model.Attrs(User{Age:29} ).FirstOrInit(u2,User{Name: "Bob"})
    fmt.Println(u2.Name,u2.Age,u2.ID)
    //Assigin:不管資料庫有沒有回傳查詢結果,在會初始化指定的欄位
    u2=new(User)
    Model.Debug().Assign(User{Age: 21}).FirstOrInit(u2,User{Name:"抱墻"})
    fmt.Println(u2.Name,u2.Age)

 

FirstOrCreate插入資料

Attrs和Assign不僅可以對宣告的結構體變數進行初始化,還可以指定FirstOrCreate將要創建的記錄,

FirstOrCreate:獲取匹配的第1條記錄, 否則根據給定的條件創建一個新的記錄 (僅支持 struct 和 map 條件)

Attrs:如果記錄未找到,將使用attr中設定的引數創建 struct 和新記錄.

Assign:不管記錄是否找到,都將引數賦值給 struct 并保存至資料庫.

    //FirstOrCreate
    u3 := new(User)
    //如果SQL條件匹配到了記錄就回傳原有記錄賦值給結構體變數,
    Model.Debug().FirstOrCreate(u3, User{Name: "嬴政"})
    fmt.Println(u3.Age, u3.ID)
    //如果SQl查詢沒有匹配到記錄就 insert 1條新記錄,回傳新記錄賦值給結構體變數,
    u3 = new(User)
    Model.Debug().Where(User{Name: "嬴胡亥"}).FirstOrCreate(u3)
    fmt.Println(u3.ID)

    //Attrs
    //如果SQL匹配到記錄,回傳原記錄并賦值給結構體變數,(不使用Attrs(User{Age: 20})中設定的引數)
    u3 = new(User)
    Model.Debug().Where(User{Name: "嬴胡亥"}).Attrs(User{Age: 20}).FirstOrCreate(u3)
    fmt.Println(u3.Name, u3.Age)
    //如果SQL沒有匹配到記錄,就使用Where(User{Name: "匹配不到嬴胡亥用戶"})和.Attrs(User{Age: 20})中的引數, insert 1條新記錄,回傳新記錄賦值給結構體變數,
    u3 = new(User)
    Model.Debug().Where(User{Name: "匹配不到嬴胡亥用戶"}).Attrs(User{Age: 2000}).FirstOrCreate(u3)
    fmt.Println(u3.Name, u3.ID)

    //Assign
    //SQL匹配到記錄就更新原記錄(update not insert new record)
    u3 = new(User)
    Model.Debug().Where(User{Name: "嬴胡亥"}).Attrs(User{Age: 20}).FirstOrCreate(u3)
    fmt.Println(u3.Name, u3.Age)
    //沒有匹配到就使用Where(User{Name: "匹配不到嬴胡亥用戶"})和.Attrs(User{Age: 20})中的引數,  insert new record,
    u3 = new(User)
    Model.Debug().Where(User{Name: "我不存在"}).Assign(User{Age: 90}).FirstOrCreate(u3)
    fmt.Println(u3.Name, u3.Age)

 

子查詢

db.Where("amount > ?", db.Table("orders").Select("AVG(amount)").Where("state = ?", "paid").SubQuery()).Find(&orders)
// SELECT * FROM "orders"  WHERE "orders"."deleted_at" IS NULL AND (amount > (SELECT AVG(amount) FROM "orders"  WHERE (state = 'paid')));

 

Select選擇欄位

Select,指定你想從資料庫中檢索出的欄位,默認會選擇全部欄位,

      //Select,指定你想從資料庫中檢索出的欄位,默認會選擇全部欄位,
	users := []User{}
	//SELECT id,name FROM `users`
	Model.Debug().Select("id,name").Find(&users)
	fmt.Println(users)
	users = []User{}
	//SELECT `name`,`age` FROM `users`
	Model.Debug().Select([]string{"name","age"}).Find(&users)
	fmt.Println(users)
	users=[]User{}
	Model.Debug().Table("users").Select("COALESCE(age,?)", 200)
	fmt.Println(users)    

  

 

排序查詢

 我們可以通過Order api對查詢的資料進行排序

	userList:=[]User{}
	//SELECT * FROM `users` ORDER BY age desc, name
	Model.Debug().Order("age desc, name").Find(&userList)
	fmt.Println(userList)
	// 多欄位排序
	userList=[]User{}
	Model.Debug().Select("id,age").Order("id desc").Order("age").Find(&userList)
	fmt.Println(userList)

  

Limit & Offset

分頁查詢Limit specify the max number of records to retrieve Offset specify the number of records to skip before starting to return the records

    //limit and offset
	//回傳3條資料
	userList:=[]User{}
	Model.Limit(3).Find(&userList)
	fmt.Println(userList)
	// 通過 -1 消除 Limit 條件
	Model.Limit(3).Find(&userList).Limit(-1).Find(&userList)
	fmt.Println(userList)
	//移動到ID=2的記錄獲取2條,分頁就是這樣搞的!
	Model.Debug().Offset(2).Limit(2).Find(&userList)
	fmt.Println(userList)

  

count獲取查詢總量

Count,該 model 能獲取的記錄總數,Count 必須是鏈式查詢的最后一個操作 ,因為它會覆寫前面的 SELECT,但如果里面使用了 count 時不會覆寫

count1:=new(int64)
Model.Debug().Find(&userList).Count(count1)
fmt.Println(*count1)

  

Group&Having 

分組和聚合

     //group by: SELECT name,sum(age) as total FROM `users` GROUP BY `name`
	type groupByage struct {
		Age  int
		Total int
	}
	groupList :=[]groupByage{}
	Model.Debug().Model(&User{}).Select("age,count(name) as total").Group("age").Find(&groupList)
	fmt.Printf("%#v\n", groupList)


	//haveing可以對group by 之后的結果,進行進一步篩選,
	//SELECT name,sum(age) as total FROM `users` WHERE name LIKE '劉%' GROUP BY `name` HAVING total >= 50
	type groupByname struct {
		Name  string
		Total int
	}
	groupList1:=[]groupByname{}
	Model.Debug().Model(&User{}).Select("name,sum(age) as total").Where("name LIKE ?", "劉%").Group("name").Having("total >= ?",50).Find(&groupList1)
	fmt.Println(groupList1)

  

join連表

type result struct {
  Name  string
  Email string
}
db.Model(&User{}).Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&result{})
// SELECT users.name, emails.email FROM `users` left join emails on emails.user_id = users.id

rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()
for rows.Next() {
  ...
}

db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&results)

// 帶引數的多表連接
db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "[email protected]").Joins("JOIN credit_cards ON credit_cards.user_id = users.id").Where("credit_cards.number = ?", "411111111111").Find(&user)

  

 

Pluck

Query single column from database and scan into a slice, if you want to query multiple columns, use Select with Scan instead

Pluck可以幫助我們獲取到table中的某1列資料并賦值給slice,

        //pluck獲取age列做位切片回傳
	var ageList []int64
	Model.Debug().Model(&User{}).Pluck("age",&ageList)
	fmt.Println(ageList)

	nameList:=new([]string)
	Model.Debug().Model(&User{}).Pluck("name",&nameList)
	fmt.Println(nameList)        

 

Scan

Scan results into a struct work similar to Find

Scan的功能類似于Find,可以把從資料庫中查詢到的結果映射到struct中,

//scan的用法
    type scanResult struct {
        Name string
        Age  int64
    }
    //類似于First()的功能
    scanResultObj := new(scanResult)
    Model.Table("users").Select("name,age").Where("name = ?", "嬴政").Scan(scanResultObj)
    fmt.Println(scanResultObj)
    //類似于Find()功能
    scanResultList := new([]scanResult)
    Model.Table("users").Select("name,age").Where("name like ?", "劉%").Scan(scanResultList)
    fmt.Println(scanResultList)

 

Scope查詢

Scopes allow you to re-use commonly logic, the shared logic needs to defined as type func(*gorm.DB) *gorm.DB

Scopes可以幫助我們把常用的查詢邏輯封裝到1個函式里面,后期使用查詢時Scope這個函式,

//名字不為空
func NameNotNull(db *gorm.DB) *gorm.DB {
    return db.Where("name is not null")
}

//查詢年齡>=18歲的用戶
func AgeLe18(db *gorm.DB) *gorm.DB {
    return db.Where("age >= ?", 18)
}

//分頁查詢
func PageData(start, count int) func(db *gorm.DB) *gorm.DB {
    return func(db *gorm.DB) *gorm.DB {
        return db.Offset(start).Limit(count)
    }
}

    //scope
    //查詢姓名不為空 年齡>=18
    userList := new([]User)
    Model.Scopes(NameNotNull, AgeLe18).Find(userList)
    fmt.Println(userList)
    //分頁查詢
    Model.Scopes(PageData(5,10)).Find(userList)
    fmt.Println(userList)

 

鏈式操作相關

 Django的Q查詢可以做組合查詢,gorm中的鏈式操作也可以,

    var userlist []User
    contionChain:=Model.Debug().Not("name is null")
    contionChain.Where("name like ?","劉%")
    contionChain.Where("age >?",10)
    contionChain.Find(&userlist)
    fmt.Println(userlist)

 

更新 update

 

Save更新所有欄位

  var userObj User
    Model.First(&userObj)
    fmt.Println(userObj)
    //save更新: 默認會修改所有欄位 
    userObj.Age=90
    //UPDATE `users` SET `id`=1,`created_at`='2020-12-24 05:29:33.978',`updated_at`='2020-12-24 13:35:08.695',`deleted_at`=NULL,`name`='特朗普',`age`=90,`active`=true WHERE `id` = 1
    Model.Debug().Save(userObj)

 

Update更新1個欄位

Model(&userObj)我在Model中能傳了1個userObj,gorm會根據userObj中的id欄位去資料庫where需要更新的記錄,

  //update:更新指定的欄位
    //根據結構體更新 1個欄位
    Model.Debug().Model(&userObj).Update("name","唐納德.特朗普")
    //根據給定的條件更新 1個欄位
    Model.Debug().Model(&userObj).Where("name = ?","唐納德.特朗普").Update("age",10)

 

Updates同時更新多個欄位

我們可以給update方法傳1個map,同時更新多個欄位,

//更新多個欄位 使用struct
    m1:=map[string]interface{}{
        "name":"唐納德.特朗普",
        "age":20,
    }
    //UPDATE `users` SET `age`=20,`name`='唐納德.特朗普',`updated_at`='2020-12-24 13:50:07.519' WHERE `id` = 1
    //注意:Model(&userObj)我在Model中能傳來1個userObj,gorm會根據userObj中的id欄位去where需要更新的值
    Model.Debug().Model(&userObj).Updates(m1)

 

Updates更新指定的欄位

有時我們接收到的map可能會包含一些我們不需要更新的欄位,那么如何指定有效欄位、排除無效欄位呢?

    //updates:更新指定欄位
    //指定age欄位進行更新
    Model.Debug().Model(&userObj).Select("age").Updates(map[string]interface{}{"name":"唐納德.-特朗普","age":9000,"active":false})
    //排除age欄位進行更新
    Model.Debug().Model(&userObj).Omit("age").Updates(map[string]interface{}{"name":"唐納德.-特朗普","age":9000,"active":false})
    

 

UpdateColumns 

UpdateColumns也叫無Hooks更新,

上面的更新操作會自動運行 model 的 BeforeUpdateAfterUpdate 方法,

更新 UpdatedAt 時間戳, 在更新時保存其 Associations, 如果你不想呼叫這些方法,你可以使用 UpdateColumn, UpdateColumns就不會更新UpdatedAt欄位,

//UpdateColumn
    Model.Debug().Model(&userObj).Update("name", "唐納德.特朗普")
    Model.Debug().Model(&userObj).UpdateColumns(map[string]interface{}{
        "name": "唐納德.-特朗普",
        "age":  200,
    })
    Model.Debug().Model(&userObj).UpdateColumns(User{Name:"唐納德.特朗普",Active: true})
    defer connectionPool.Close()

 

批量更新多條記錄

 注意在批量更新的時候不會更新 UpdatedAt 欄位,

    //批量更新
    AffectedRows:=Model.Debug().Table("users").Where("id in (?)", []int{1, 2}).Updates(map[string]interface{}{
        "age": 21,
    }).RowsAffected
    fmt.Println("更新的行數",AffectedRows)

 

全表更新

我想要1張表中的某個欄位全部更新怎么辦?還記得Django中的F在原資料的基礎上+1?

  //全域更新
    //錯誤的全域更新方式,之前是可以的!!
    err := Model.Model(&User{}).Update("name", "二狗").Error // 錯誤的寫法!!gorm.ErrMissingWhereClause
    fmt.Println(err)
    //全域更新方式1
    Model.Debug().Exec("UPDATE users SET age = ?", "18")
    //讓user表中用戶年齡在原來的基礎上+2,Expr 子查詢
    Model.Debug().Session(&gorm.Session{AllowGlobalUpdate: true}).Model(User{}).Update("age", gorm.Expr("age+ ?", 100))

 

洗掉delete

最后就是洗掉了~

洗掉1條記錄

我跟可以根據物件洗掉一條記錄,注意必須指定物件的主鍵否則會觸發 批量 Delete,也可以根據主鍵直接洗掉1條記錄,

  //根據物件洗掉:洗掉物件需要指定主鍵,否則會觸發 批量 Delete
    u:=new(User)
    u.ID=1
    Model.Debug().Delete(u)
    //根據主鍵洗掉
    Model.Debug().Delete(&User{},10)
    //根據主鍵洗掉多個
    Model.Debug().Delete(&User{},[]int{4,11})    

 

批量洗掉

gorm中都是軟洗掉,

    //2.批量洗掉
    deletedUsers:=[]User{}
    Model.Debug().Where("name like ?","唐納德%").Delete(User{})
    Model.Debug().Delete(deletedUsers,"name like ?","嬴%")
    fmt.Println(deletedUsers)

 

全表洗掉

 清空表中的內容

//全域洗掉
    //1.錯誤的方式
    err:=Model.Delete(&User{}).Error
    fmt.Println(err)
    //正確方式
    Model.Where("1 = 1").Delete(&User{})
    Model.Exec("truncate table users")
    Model.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&User{})

 

 

 

從別人創建的表中匯出model 

參考

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/239988.html

標籤:MySQL

上一篇:學生資訊管理系統怎么搞啊?求大佬賜教

下一篇:神奇的 SQL 之 HAVING → 容易被輕視的主角

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more