成功最有效的方法就是向有经验的人学习!

GORM入门篇

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"}]} 
}
内容查看本文隐藏内容查看需要消耗5土豆币,请先
土豆币按需购买,不退换,请考虑清楚后购买。
赞(0) 打赏
未经允许不得转载:陈桂林博客 » GORM入门篇
分享到

大佬们的评论 抢沙发

全新“一站式”建站,高质量、高售后的一条龙服务

微信 抖音 支付宝 百度 头条 快手全平台打通信息流

橙子建站.极速智能建站8折购买虚拟主机

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续给力更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫打赏

微信扫一扫打赏

登录

找回密码

注册