GORM入门
什么是ORM?
orm是一种术语而不是软件
- 1)orm英文全称object relational mapping,就是 对象映射关系 程序
- 2)简单来说类似python这种面向对象的程序来说一切皆对象,但是我们使用的数据库却都是关系型的
- 3)为了保证一致的使用习惯,通过 orm将编程语言的对象模型和数据库的关系模型建立映射关系
- 4)这样我们直接 使用编程语言的对象模型进行操作数据库 就可以了,而不用直接使用sql语言
什么是GORM?
https://gorm.io/zh_CN/docs/index.html
GORM是一个神奇的,对开发人员友好的 Golang ORM 库
- 全特性 ORM (几乎包含所有特性)
- 模型关联 (一对一, 一对多,一对多 (反向), 多对多, 多态关联)
- 钩子 (Before/After Create/Save/Update/Delete/Find)
- 预加载
- 事务
- 复合主键
- SQL 构造器
- 自动迁移
- 日志
- 基于GORM回调编写可扩展插件
- 全特性测试覆盖
- 开发者友好
GORM(v3)基本使用
1、安装
go get -u gorm.io/gorm
2、连接MySQL
先创建一个数据库
mysql> create database test_db charset utf8; # 创建数据库
mysql> use test_db; # 切换到数据库
mysql> show tables; # 查看是否生成表
+-------------------+
| Tables_in_test_db |
+-------------------+
| users |
+-------------------+
mysql> desc users; # 查看表的字段是否正常
创建mysql连接
https://gorm.io/zh_CN/docs/connecting_to_the_database.html
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
dsn := "root:1@tcp(127.0.0.1:3306)/test_db? charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println(err)
}
fmt.Println(db) // &{0xc00018a630 <nil> 0 0xc000198380 1}
}
3、自动创建表
https://gorm.io/zh_CN/docs/models.html
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// User 表的结构体ORM映射
type User struct {
Id int64 `gorm:"primary_key" json:"id"`
Username string
Password string
}
func main() {
// 1、连接数据库
dsn := "root:1@tcp(127.0.0.1:3306)/test_db? charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 2、自动创建表
db.AutoMigrate(User{}, )
}
4、基本增删改查
https://gorm.io/zh_CN/docs/index.html
package main
import (
"fmt"
"gorm.io/gorm"
)
// User 表的结构体ORM映射
type User struct {
Id int64 `gorm:"primary_key" json:"id"`
Username string
Password string
}
您暂时无权查看此隐藏内容!
模型定义
https://gorm.io/zh_CN/docs/models.html
1、模型定义
模型一般都是普通的 Golang 的结构体,Go的基本数据类型,或者指针。
例子:
type User struct {
Id int64 `gorm:"primary_key" json:"id"`
Name string
CreatedAt *time.Time `json:"createdAt" gorm:"column:create_at"`
Email string `gorm:"type:varchar(100);unique_index"` // 唯一索引
Role string `gorm:"size:255"` //设置字段的大小为255个字 节
MemberNumber *string `gorm:"unique;not null"` // 设置 memberNumber 字段唯一且不为空
Num int `gorm:"AUTO_INCREMENT"` // 设置 Num字段自增
Address string `gorm:"index:addr"` // 给Address 创建一个 名字是 `addr`的索引
IgnoreMe int `gorm:"-"` //忽略这个字段
}
2、支持结构标签
标签是声明模型时可选的标记
标签 | 说明 |
---|---|
Column | 指定列的名称 |
Type | 指定列的类型 |
Size | 指定列的大小,默认是 255 |
PRIMARY_KEY | 指定一个列作为主键 |
UNIQUE | 指定一个唯一的列 |
DEFAULT | 指定一个列的默认值 |
PRECISION | 指定列的数据的精度 |
NOT NULL | 指定列的数据不为空 |
AUTO_INCREMENT | 指定一个列的数据是否自增 |
INDEX | 创建带或不带名称的索引,同名创建复合索引 |
UNIQUE_INDEX | 类似 索引 ,创建一个唯一的索引 |
EMBEDDED | 将 struct 设置为 embedded |
EMBEDDED_PREFIX | 设置嵌入式结构的前缀名称 |
– | 忽略这些字段 |
一对多关联查询
https://gorm.io/zh_CN/docs/has_many.html
一对多入门
1、has many介绍
has many 关联就是创建和另一个模型的一对多关系
例如, 例如每一个用户都拥有多张信用卡,这样就是生活中一个简单的一对多关系
// 用户有多张信用卡,UserID 是外键
type User struct {
gorm.Model
CreditCards []CreditCard
}
type CreditCard struct {
gorm.Model
Number string
UserID uint // 默认会在 CreditCard 表中生成 UserID 字段作为 与User表关联的外键ID
}
2、外键
为了定义一对多关系, 外键是必须存在的,默认外键的名字是 所有者类型的名字加上它的主键(UserId) 。
就像上面的例子,为了定义一个属于 User 的模型,外键就应该为 UserID 。
使用其他的字段名作为外键, 你可以通过 foreignkey 来定制它, 例如:
type User struct {
gorm.Model
// foreignkey:UserRefer 可以自己指定外键关联字段名为:UserRefer
// 默认外键字段名是 UserId,你也可以自己修改
CreditCards []CreditCard `gorm:"foreignkey:UserRefer"`
}
type CreditCard struct {
gorm.Model
Number string
UserRefer uint
}
3、外键关联
GORM 通常使用所有者的主键作为外键的值, 在上面的例子中,它就是 User 的 ID 。
当你分配信用卡给一个用户, GORM 将保存用户 ID 到信用卡表的 UserID 字段中。
你能通过 association_foreignkey 来改变它
type User struct {
gorm.Model
MemberNumber string
// 默认CreditCard会使用User表的Id作为外键,association_foreignkey:MemberNumber 指定使用 MemberNumber 作为外键关联
CreditCards []CreditCard `gorm:"foreignkey:UserMemberNumber;association_foreignkey:MemberNumber"`
}
type CreditCard struct {
gorm.Model
Number string
UserMemberNumber string
}
创建一对多表
https://gorm.io/zh_CN/docs/associations.html#%E8%87%AA%E5%8A%A8%E5%88%9B%E5%BB%BA%E3%80%81%E6%9B%B4%E6%96%B0
#重写外键
https://gorm.io/zh_CN/docs/has_many.html#%E9%87%8D%E5%86%99%E5%A4%96%E9%94%AE
#外键约束
https://gorm.io/zh_CN/docs/has_many.html#%E5%A4%96%E9%94%AE%E7%BA%A6%E6%9D%9F
1、表结构定义
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
/*
constraint:OnUpdate:CASCADE 【当User表更新,也会同步给CreditCards】 // 外键约束
OnDelete:SET NULL 【当User中数据被删除时,CreditCard关联设置为 NULL,不删除记录】
*/
type User struct {
gorm.Model
Username string `json:"username" gorm:"column:username"`
CreditCards []CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
func main() {
// 0、连接数据库
dsn := "root:1@tcp(127.0.0.1:3306)/test_db? charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 创建表结构
db.AutoMigrate(User{}, CreditCard{})
// 1、创建一对多
user := User{
Username: "zhangsan",
CreditCards: []CreditCard{
{Number: "0001"},
{Number: "0002"},
},
}
db.Create(&user)
// 2、为已存在用户添加信用卡
u := User{Username: "zhangsan"}
db.First(&u)
//fmt.Println(u.Username)
db.Model(&u).Association("CreditCards").Append([]CreditCard{
{Number: "0003"},
})
}
2、创建结果说明
我们没有指定 foreignkey,所以会与 UserID字段自动建立外键关联关系
3、一对多Association
使用 Association 方法, 需要把把 User 查询好, 然后根据 User 定义中指定的AssociationForeignKey 去查找 CreditCard
https://gorm.io/zh_CN/docs/associations.html#%E6%9F%A5%E6%89%BE%E5%85%B3%E8%81%94
package main
import (
"encoding/json"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
/*
constraint:OnUpdate:CASCADE 【当User表更新,也会同步给CreditCards】
OnDelete:SET NULL 【当User中数据被删除时,CreditCard关联设置为 NULL,不删除记录】
*/
type User struct {
gorm.Model
Username string `json:"username" gorm:"column:username"`
CreditCards []CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
func main() {
// 0、连接数据库
dsn := "root:1@tcp(127.0.0.1:3306)/test_db? charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 1、查找 用户名为 zhangsan 的所有信用卡信息
u := User{Username: "zhangsan"} // Association必须要先查出User才能关联查询对应的 CreditCard
db.First(&u)
err := db.Model(&u).Association("CreditCards").Find(&u.CreditCards)
if err != nil {
fmt.Println(err)
}
strUser, _ := json.Marshal(&u)
fmt.Println(string(strUser))
}
打印结果如下
{
"ID":1,
"username":"zhangsan",
"CreditCards":[
{
"ID":1,
"Number":"0001",
"UserID":1
},
...
]
}
4、一对多Preload
使用 Preload 方法, 在查询 User 时先去获取 CreditCard 的记录
https://gorm.io/zh_CN/docs/preload.html
package main
import (
"encoding/json"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
/*
constraint:OnUpdate:CASCADE 【当User表更新,也会同步给CreditCards】
OnDelete:SET NULL 【当User中数据被删除时,CreditCard关联设置为 NULL,不删除记录】
*/
type User struct {
gorm.Model
Username string `json:"username" gorm:"column:username"`
CreditCards []CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
func main() {
// 0、连接数据库
dsn := "root:1@tcp(127.0.0.1:3306)/test_db? charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 1、预加载: 查找 user 时预加载相关 CreditCards
// users := User{Username: "zhangsan"} // 只查找张三用户的信用卡信息
users := []User{}
db.Preload("CreditCards").Find(&users)
strUser, _ := json.Marshal(&users)
fmt.Println(string(strUser))
}
输出结果:
[
{
"ID":1,
"username":"zhangsan",
"CreditCards":[
{
"ID":1,
"Number":"0001",
"UserID":1
},
...
]
}
]
多对多
多对多入门
https://gorm.io/zh_CN/docs/many_to_many.html
1、Many To Many
- Many to Many 会在两个 model 中添加一张连接表。
- 例如,您的应用包含了 user 和 language,且一个 user 可以说多种 language,多个 user 也可以说一种 language。
- 当使用 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
}
2、反向引用
// 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;"`
}
3、重写外键
对于 many2many 关系,连接表会同时拥有两个模型的外键
type User struct {
gorm.Model
Languages []Language `gorm:"many2many:user_languages;"`
}
type Language struct {
gorm.Model
Name string
}
// 连接表:user_languages
// foreign key: user_id, reference: users.id
// foreign key: language_id, reference: languages.id
若要重写它们,可以使用标签 foreignKey 、 references 、 joinforeignKey 、joinReferences 。
当然,您不需要使用全部的标签,你可以仅使用其中的一个重写部分的外键、引用。
type User struct {
gorm.Model
Profiles []Profile `gorm:"many2many:user_profiles;foreignKey:Refer;joinForeignKey:UserReferID;References: UserRefer;joinReferences:ProfileRefer"`
Refer uint `gorm:"index:,unique"`
}
type Profile struct {
gorm.Model
Name string
UserRefer uint `gorm:"index:,unique"`
}
// 会创建连接表:user_profiles
// foreign key: user_refer_id, reference: users.refer
// foreign key: profile_refer, reference: profiles.user_refer
创建多对多表
1、m2m生成第三张表
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// User 拥有并属于多种 language,`user_languages` 是连接表
type User struct {
gorm.Model
Languages []Language `gorm:"many2many:user_languages;"`
}
type Language struct {
gorm.Model
Name string
}
func main() {
// 0、连接数据库
dsn := "root:1@tcp(127.0.0.1:3306)/test_db? charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 1、自动创建多对多表结构
db.AutoMigrate(
User{},
Language{},
)
}
生成如下三张表
2、自定义第三张表
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"time"
)
type Person struct {
ID int
Name string
Addresses []Address `gorm:"many2many:person_addresses;"`
}
type Address struct {
ID uint
Name string
}
type PersonAddress struct {
PersonID int `gorm:"primaryKey"`
AddressID int `gorm:"primaryKey"`
CreatedAt time.Time
DeletedAt gorm.DeletedAt
}
//func (PersonAddress) BeforeCreate(db *gorm.DB) (err error) {
// // 修改 Person 的 Addresses 字段的连接表为 PersonAddress
// // PersonAddress 必须定义好所需的外键,否则会报错
// err = db.SetupJoinTable(&Person{}, "Addresses", &PersonAddress{})
// if err != nil {
// fmt.Println("err", err)
// }
// return nil
// }
func main() {
// 0、连接数据库
dsn := "root:1@tcp(127.0.0.1:3306)/test_db? charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 1、自动创建多对多表结构
db.AutoMigrate(
Person{},
Address{},
)
// 2、添加数据
persons := Person{
ID: 1,
Name: "zhangsan",
Addresses: []Address{
{ID: 1, Name: "bj"},
{ID: 2, Name: "sh"},
},
}
db.Create(&persons)
}
生成三张表如下
3、多对多Preload
https://gorm.io/zh_CN/docs/preload.html
package main
import (
"encoding/json"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"time"
)
type Person struct {
ID int
Name string
Addresses []Address `gorm:"many2many:person_addresses;"`
}
type Address struct {
ID uint
Name string
}
type PersonAddress struct {
PersonID int `gorm:"primaryKey"`
AddressID int `gorm:"primaryKey"`
CreatedAt time.Time
DeletedAt gorm.DeletedAt
}
func main() {
// 0、连接数据库
dsn := "root:1@tcp(127.0.0.1:3306)/test_db? charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 1、获取 name="zhangsan" 用户的地址
persons := []Person{}
db.Preload("Addresses").Find(&persons)
strPersons, _ := json.Marshal(&persons)
fmt.Println(string(strPersons))
// [{"ID":1,"Name":"zhangsan","Addresses":[{"ID":1,"Name":"bj"}, {"ID":2,"Name":"sh"}]}]
// 2、获取 name="zhangsan" 用户的地址
person := Person{Name: "zhangsan"}
db.Preload("Addresses").Find(&person)
strPerson, _ := json.Marshal(&person)
fmt.Println(string(strPerson))
// {"ID":1,"Name":"zhangsan","Addresses":[{"ID":1,"Name":"bj"}, {"ID":2,"Name":"sh"}]}
}