golang?Gorm框架講解
1.gorm介紹
1.1介紹
全功能 ORM 關(guān)聯(lián) (Has One,Has Many,Belongs To,Many To Many,多態(tài),單表繼承) Create,Save,Update,Delete,F(xiàn)ind 中鉤子方法 支持 Preload、Joins 的預(yù)加載 事務(wù),嵌套事務(wù),Save Point,Rollback To Saved Point Context,預(yù)編譯模式,DryRun 模式 批量插入,F(xiàn)indInBatches,F(xiàn)ind/Create with Map,使用 SQL 表達式、Context Valuer 進行 CRUD SQL 構(gòu)建器,Upsert,數(shù)據(jù)庫鎖,Optimizer/Index/Comment Hint,命名參數(shù),子查詢 復(fù)合主鍵,索引,約束 Auto Migration 自定義 Logger 靈活的可擴展插件 API:Database Resolver(多數(shù)據(jù)庫,讀寫分離)、Prometheus… 每個特性都經(jīng)過了測試的重重考驗 開發(fā)者友好
1.2安裝
go get -u gorm.io/gorm go get -u gorm.io/driver/sqlite
2.使用
2.1創(chuàng)建表
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
//模型結(jié)構(gòu)
type Student struct {
Id int
Name string
Age int
}
type User struct {
gorm.Model
Name string `gorm:"type:varchar(20);not null"`
Telephone string `gorm:"varchar(110;not null;unique"`
Password string `gorm:"size:255;not null"`
}
func main() {
//使用dsn連接到數(shù)據(jù)庫,grom自帶的數(shù)據(jù)庫池
//賬號:密碼@連接方式(ip地址:端口號)/數(shù)據(jù)庫?語言方式,時區(qū)(未設(shè)置時區(qū)的話采用8小時制度)
dsn := "root:mysql@tcp(127.0.0.1:3306)/gotest?charset=utf8mb4&parseTime=True&loc=Local"
conn, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) //使用mysq連接數(shù)據(jù)庫,第二個參數(shù)可以增加更多的配置(可有可無)
if err != nil {
fmt.Println(err)
}
conn.AutoMigrate(&Student{}) //創(chuàng)建表?判斷是否表結(jié)構(gòu)存在
}
//多表創(chuàng)建
db.AutoMigrate(&Company{}, &Worker{})
2.2.添加數(shù)據(jù)
stu := &Student{
Id: 3,
Name: "li333",
Age: 30,
}
res := conn.Create(stu) //向數(shù)據(jù)庫中插入數(shù)據(jù) ,它的返回值只有一個類型,沒有error類型
//注:如果上面寫成stu := Student{...},則這里寫成Create(&stu)
if res.Error != nil { //判斷是否插入數(shù)據(jù)出錯
fmt.Println(res.Error)
}2.3.查詢數(shù)據(jù)
var student Student
//查詢First查詢一條
conn.First(&student)
fmt.Println(student)
fmt.Println(student.Id)
//條件查詢
res := conn.First(&student, "name=? and id=?", "yang", 1)
fmt.Println(res)
//查詢所有 Find
var stu []Student
conn.Table("students").Find(&stu)
for _, v := range stu {
fmt.Println(v.Name)
}
// IN
var students []Student
conn.Table("students").Where("name IN ?", []string{"abc", "bili"}).Find(&students)
fmt.Println(students)
// LIKE
db.Where("name LIKE ?", "%jin%").Find(&users)
// AND
db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&users)
// Time
db.Where("updated_at > ?", time.Date(2022,05,20,0,0,0,0,&time.Location{})).Find(&users)
// BETWEEN
db.Where("created_at BETWEEN ? AND ?", time.Date(2022,05,20,0,0,0,0,&time.Location{}), time.Now()).Find(&users)
2.4更新數(shù)據(jù)
//更新數(shù)據(jù)
conn.Table("students").Where("id=?", 1).Update("name", "ttt")
conn.Table("students").Where("id=?", 2).Updates(&Student{Name: "bili", Age: 10})
//按主鍵更新,傳入結(jié)構(gòu)體對象,根據(jù)對應(yīng)主鍵更新相應(yīng)內(nèi)容
dbConn.Table("user").Save(&user1)2.5刪除數(shù)據(jù)
conn.Table("students").Where("id=?", 1).Delete(&Student{})2.6執(zhí)行原生sql
conn.Raw("select * from students where id=?", 3).Scan(&student)
fmt.Println(student)
db.Exec("DROP TABLE users")
db.Exec("UPDATE orders SET shipped_at=? WHERE id IN ?", time.Now(), []int64{1,2,3})3.一對一
3.1創(chuàng)建表
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type User struct {
gorm.Model
CreditCard CreditCard
Name string
}
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
func main() {
//使用dsn連接到數(shù)據(jù)庫,grom自帶的數(shù)據(jù)庫池
//賬號:密碼@連接方式(ip地址:端口號)/數(shù)據(jù)庫?語言方式,時區(qū)(未設(shè)置時區(qū)的話采用8小時制度)
dsn := "root:mysql@tcp(127.0.0.1:3306)/crow?charset=utf8mb4&parseTime=True&loc=Local"
conn, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) //使用mysq連接數(shù)據(jù)庫,第二個參數(shù)可以增加更多的配置(可有可無)
if err != nil {
fmt.Println(err)
}
conn.AutoMigrate(&User{})
conn.AutoMigrate(&CreditCard{})
//創(chuàng)建表?判斷是否表結(jié)構(gòu)存在
user := &User{
Name: "李四",
}
conn.Create(user)
card := &CreditCard{
Number: "123",
UserID: 1,
}
conn.Create(card)
}3.2多態(tài)關(guān)聯(lián)
//多態(tài)關(guān)聯(lián)
//GORM 為 has one 和 has many 提供了多態(tài)關(guān)聯(lián)支持,它會將擁有者實體的表名、主鍵值都保存到多態(tài)類型的字段中。
type Cat struct {
ID int
Name string
Toy Toy `gorm:"polymorphic:Owner;"`
}
type Dog struct {
ID int
Name string
Toy Toy `gorm:"polymorphic:Owner;"`
}
type Toy struct {
ID int
Name string
OwnerID int
OwnerType string
}
db.Create(&Dog{Name: "dog1", Toy: Toy{Name: "toy1"}})
// INSERT INTO `dogs` (`name`) VALUES ("dog1")
// INSERT INTO `toys` (`name`,`owner_id`,`owner_type`) VALUES ("toy1","1","dogs")3.3外鍵約束
你可以通過為標簽 constraint 配置 OnUpdate、OnDelete 實現(xiàn)外鍵約束,在使用 GORM 進行遷移時它會被創(chuàng)建,例如:
type User struct {
gorm.Model
Name string
CompanyID int
Company Company `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}
type Company struct {
ID int
Name string
}4.一對多
Has Many
has many 與另一個模型建立了一對多的連接。 不同于 has one,擁有者可以有零或多個關(guān)聯(lián)模型。
例如,您的應(yīng)用包含 user 和 credit card 模型,且每個 user 可以有多張 credit card。
// User 有多張 CreditCard,UserID 是外鍵
type User struct {
gorm.Model
CreditCards []CreditCard
}
type CreditCard struct {
gorm.Model
Number string
UserID uint
}package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type User struct {
gorm.Model
MemberNumber string `gorm:"varchar(110;not null;unique"`
CreditCards []CreditCard `gorm:"foreignKey:UserNumber;references:MemberNumber"`
Name string
}
type CreditCard struct {
gorm.Model
Number string
UserNumber string `gorm:"varchar(110;not null;unique"`
}
func main() {
//使用dsn連接到數(shù)據(jù)庫,grom自帶的數(shù)據(jù)庫池
//賬號:密碼@連接方式(ip地址:端口號)/數(shù)據(jù)庫?語言方式,時區(qū)(未設(shè)置時區(qū)的話采用8小時制度)
dsn := "root:mysql@tcp(127.0.0.1:3306)/crow?charset=utf8mb4&parseTime=True&loc=Local"
conn, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) //使用mysq連接數(shù)據(jù)庫,第二個參數(shù)可以增加更多的配置(可有可無)
if err != nil {
fmt.Println(err)
}
conn.AutoMigrate(&User{}, &CreditCard{})
user := User{
Name: "ttt3",
MemberNumber: "1003",
}
conn.Create(&user)
card := CreditCard{
Number: "111",
UserNumber: user.MemberNumber,
}
conn.Create(&card)
}
5.多對多
Many To Many
Many to Many 會在兩個 model 中添加一張連接表。
例如,您的應(yīng)用包含了 user 和 language,且一個 user 可以說多種 language,多個 user 也可以說一種 language。
// User 擁有并屬于多種 language,`user_languages` 是連接表
type User struct {
gorm.Model
Languages []Language `gorm:"many2many:user_languages;"`
}
type Language struct {
gorm.Model
Name string
}當使用 GORM 的 AutoMigrate 為 User 創(chuàng)建表時,GORM 會自動創(chuàng)建連接表
反向引用
// User 擁有并屬于多種 language,`user_languages` 是連接表
type User struct {
gorm.Model
Languages []*Language `gorm:"many2many:user_languages;"`
}
type Language struct {
gorm.Model
Name string
Users []*User `gorm:"many2many:user_languages;"`
}重寫外鍵
對于 many2many 關(guān)系,連接表會同時擁有兩個模型的外鍵,例如:
type User struct {
gorm.Model
Languages []Language `gorm:"many2many:user_languages;"`
}
type Language struct {
gorm.Model
Name string
}
// Join Table: user_languages
// foreign key: user_id, reference: users.id
// foreign key: language_id, reference: languages.id若要重寫它們,可以使用標簽 foreignKey、reference、joinforeignKey、joinReferences。當然,您不需要使用全部的標簽,你可以僅使用其中的一個重寫部分的外鍵、引用。
type User struct {
gorm.Model
Profiles []Profile `gorm:"many2many:user_profiles;foreignKey:Refer;joinForeignKey:UserReferID;References:UserRefer;JoinReferences:UserRefer"`
Refer uint
}
type Profile struct {
gorm.Model
Name string
UserRefer uint
}
// 會創(chuàng)建連接表:user_profiles
// foreign key: user_refer_id, reference: users.refer
// foreign key: profile_refer, reference: profiles.user_refer自引用 Many2Many
自引用 many2many 關(guān)系
type User struct {
gorm.Model
Friends []*User `gorm:"many2many:user_friends"`
}
// 會創(chuàng)建連接表:user_friends
// foreign key: user_id, reference: users.id
// foreign key: friend_id, reference: users.id6.獲取多表數(shù)據(jù)
預(yù)加載
GORM 允許在 Preload 的其它 SQL 中直接加載關(guān)系,例如:
type User struct {
gorm.Model
Username string
Orders []Order
}
type Order struct {
gorm.Model
UserID uint
Price float64
}
// 查找 user 時預(yù)加載相關(guān) Order
db.Preload("Orders").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4);
db.Preload("Orders").Preload("Profile").Preload("Role").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4); // has many
// SELECT * FROM profiles WHERE user_id IN (1,2,3,4); // has one
// SELECT * FROM roles WHERE id IN (4,5,6); // belongs toJoins 預(yù)加載
Preload 在一個單獨查詢中加載關(guān)聯(lián)數(shù)據(jù)。而 Join Preload 會使用 inner join 加載關(guān)聯(lián)數(shù)據(jù),例如:
db.Joins("Company").Joins("Manager").Joins("Account").First(&user, 1)
db.Joins("Company").Joins("Manager").Joins("Account").First(&user, "users.name = ?", "jinzhu")
db.Joins("Company").Joins("Manager").Joins("Account").Find(&users, "users.id IN ?", []int{1,2,3,4,5})注意
Join Preload適用于一對一的關(guān)系,例如:has one,belongs to
預(yù)加載全部
與創(chuàng)建、更新時使用 Select 類似,clause.Associations 也可以和 Preload 一起使用,它可以用來 預(yù)加載 全部關(guān)聯(lián),例如:
type User struct {
gorm.Model
Name string
CompanyID uint
Company Company
Role Role
}
db.Preload(clause.Associations).Find(&users)帶條件的預(yù)加載
GORM 允許帶條件的 Preload 關(guān)聯(lián),類似于內(nèi)聯(lián)條件
// 帶條件的預(yù)加載 Order
db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4) AND state NOT IN ('cancelled');
db.Where("state = ?", "active").Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
// SELECT * FROM users WHERE state = 'active';
// SELECT * FROM orders WHERE user_id IN (1,2) AND state NOT IN ('cancelled');自定義預(yù)加載 SQL
您可以通過 func(db *gorm.DB) *gorm.DB 實現(xiàn)自定義預(yù)加載 SQL,例如:
db.Preload("Orders", func(db *gorm.DB) *gorm.DB {
return db.Order("orders.amount DESC")
}).Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4) order by orders.amount DESC;嵌套預(yù)加載
GORM 支持嵌套預(yù)加載,例如:
db.Preload("Orders.OrderItems.Product").Preload("CreditCard").Find(&users)
// 自定義預(yù)加載 `Orders` 的條件
// 這樣,GORM 就不會加載不匹配的 order 記錄
db.Preload("Orders", "state = ?", "paid").Preload("Orders.OrderItems").Find(&users)到此這篇關(guān)于golang Gorm框架的文章就介紹到這了,更多相關(guān)golang Gorm框架內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

