golang Gorm框架讲解
作者:BigHead777
1.gorm介绍
1.1介绍
全功能 ORM 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承) Create,Save,Update,Delete,Find 中钩子方法 支持 Preload、Joins 的预加载 事务,嵌套事务,Save Point,Rollback To Saved Point Context,预编译模式,DryRun 模式 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询 复合主键,索引,约束 Auto Migration 自定义 Logger 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus… 每个特性都经过了测试的重重考验 开发者友好
1.2安装
go get -u gorm.io/gorm go get -u gorm.io/driver/sqlite
2.使用
2.1创建表
package main import ( "fmt" "gorm.io/driver/mysql" "gorm.io/gorm" ) //模型结构 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连接到数据库,grom自带的数据库池 //账号:密码@连接方式(ip地址:端口号)/数据库?语言方式,时区(未设置时区的话采用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连接数据库,第二个参数可以增加更多的配置(可有可无) if err != nil { fmt.Println(err) } conn.AutoMigrate(&Student{}) //创建表?判断是否表结构存在 } //多表创建 db.AutoMigrate(&Company{}, &Worker{})
2.2.添加数据
stu := &Student{ Id: 3, Name: "li333", Age: 30, } res := conn.Create(stu) //向数据库中插入数据 ,它的返回值只有一个类型,没有error类型 //注:如果上面写成stu := Student{...},则这里写成Create(&stu) if res.Error != nil { //判断是否插入数据出错 fmt.Println(res.Error) }
2.3.查询数据
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更新数据
//更新数据 conn.Table("students").Where("id=?", 1).Update("name", "ttt") conn.Table("students").Where("id=?", 2).Updates(&Student{Name: "bili", Age: 10}) //按主键更新,传入结构体对象,根据对应主键更新相应内容 dbConn.Table("user").Save(&user1)
2.5删除数据
conn.Table("students").Where("id=?", 1).Delete(&Student{})
2.6执行原生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创建表
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连接到数据库,grom自带的数据库池 //账号:密码@连接方式(ip地址:端口号)/数据库?语言方式,时区(未设置时区的话采用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连接数据库,第二个参数可以增加更多的配置(可有可无) if err != nil { fmt.Println(err) } conn.AutoMigrate(&User{}) conn.AutoMigrate(&CreditCard{}) //创建表?判断是否表结构存在 user := &User{ Name: "李四", } conn.Create(user) card := &CreditCard{ Number: "123", UserID: 1, } conn.Create(card) }
3.2多态关联
//多态关联 //GORM 为 has one 和 has many 提供了多态关联支持,它会将拥有者实体的表名、主键值都保存到多态类型的字段中。 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
实现外键约束,在使用 GORM 进行迁移时它会被创建,例如:
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,拥有者可以有零或多个关联模型。
例如,您的应用包含 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连接到数据库,grom自带的数据库池 //账号:密码@连接方式(ip地址:端口号)/数据库?语言方式,时区(未设置时区的话采用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连接数据库,第二个参数可以增加更多的配置(可有可无) 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 中添加一张连接表。
例如,您的应用包含了 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
创建表时,GORM 会自动创建连接表
反向引用
// 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
关系,连接表会同时拥有两个模型的外键,例如:
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 } // 会创建连接表:user_profiles // foreign key: user_refer_id, reference: users.refer // foreign key: profile_refer, reference: profiles.user_refer
自引用 Many2Many
自引用 many2many 关系
type User struct { gorm.Model Friends []*User `gorm:"many2many:user_friends"` } // 会创建连接表:user_friends // foreign key: user_id, reference: users.id // foreign key: friend_id, reference: users.id
6.获取多表数据
预加载
GORM 允许在 Preload
的其它 SQL 中直接加载关系,例如:
type User struct { gorm.Model Username string Orders []Order } type Order struct { gorm.Model UserID uint Price float64 } // 查找 user 时预加载相关 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 to
Joins 预加载
Preload
在一个单独查询中加载关联数据。而 Join Preload
会使用 inner join 加载关联数据,例如:
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
适用于一对一的关系,例如:has one
,belongs to
预加载全部
与创建、更新时使用 Select
类似,clause.Associations
也可以和 Preload
一起使用,它可以用来 预加载
全部关联,例如:
type User struct { gorm.Model Name string CompanyID uint Company Company Role Role } db.Preload(clause.Associations).Find(&users)
带条件的预加载
GORM 允许带条件的 Preload 关联,类似于内联条件
// 带条件的预加载 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');
自定义预加载 SQL
您可以通过 func(db *gorm.DB) *gorm.DB
实现自定义预加载 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;
嵌套预加载
GORM 支持嵌套预加载,例如:
db.Preload("Orders.OrderItems.Product").Preload("CreditCard").Find(&users) // 自定义预加载 `Orders` 的条件 // 这样,GORM 就不会加载不匹配的 order 记录 db.Preload("Orders", "state = ?", "paid").Preload("Orders.OrderItems").Find(&users)
到此这篇关于golang Gorm框架的文章就介绍到这了,更多相关golang Gorm框架内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!