golang编程语言操作GORM快速上手篇

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 使用Go语言的GORM库进行数据库操作的教程,涵盖了GORM的基本概念、基本使用、关联查询以及多对多关系处理等内容。

一.GORM概述

1.学习方法

3w1h指What、Why、Where、How。

学技术也有方法可言,比如学习一个新的技术gorm:
    - 新手期:
        先到百度搜索几篇基本的用法案例,粘贴过来测试一下,测试通了说明你对grom有一个基础的了解。
    - 筑基期:
        到官方系统的整理,最好整理成博客,以便于以后用的时候方便查询,但这只是学会了基础语法。
    - 结丹期:
        如何将学到的东西融入到项目中,最好给自己找几个需求,然后练习实现,从而不断让自己的技术沉淀。
        如果没有案例的话,可以在GitHub或者gitee上找一些开源项目模仿跑通。
        如果你真的能做到这个阶段,保守估计,想必你的薪资应该不会低于: 35K+
    - 化神期:
        读源码和实现原理,参加过大厂面试的小伙伴应该都知道,他们很喜欢为什么问底层原理,其实了解底层原理有助于咱们做故障排查。
        比如公司要实现一个CMDB系统,你如果了解类似相关产品的实现方案的底层原理,想必你动手写应该不会毫无头绪。

2.orm是一种术语而不是软件

- orm英文全称object relational mapping,就是 对象映射关系 程序

- 简单来说类似python这种面向对象的程序来说一切皆对象,但是我们使用的数据库却都是关系型的

- 为了保证一致的使用习惯,通过orm将编程语言的对象模型和数据库的关系模型建立映射关系

- 这样我们直接使用编程语言的对象模型进行操作数据库就可以了,而不用直接使用sql语言

3.什么是grom

gorm是一个使用Go语言编写的ORM框架。它文档齐全,对开发者友好,支持主流数据库。

gorm官方中文文档:https://gorm.io/zh_CN/docs/

二.GORM基本使用

1.安装gorm

go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
go get -u gorm.io/driver/mysql

2.创建数据库

    1.创建数据库和表信息
CREATE DATABASE yinzhengjie CHARSET utf8mb4;
USE yinzhengjie;
CREATE TABLE users(
    id BIGINT(20) PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID',
    username VARCHAR(255) NOT NULL COMMENT '用户名',
    password VARCHAR(255) NOT NULL COMMENT '密码',
    status ENUM('active', 'inactive', 'deleted') NOT NULL DEFAULT 'active' COMMENT '用户状态'
);


    2.查看表结构信息
mysql> DESC users;
+----------+-------------------------------------+------+-----+---------+----------------+
| Field    | Type                                | Null | Key | Default | Extra          |
+----------+-------------------------------------+------+-----+---------+----------------+
| id       | bigint                              | NO   | PRI | NULL    | auto_increment |
| username | varchar(255)                        | NO   |     | NULL    |                |
| password | varchar(255)                        | NO   |     | NULL    |                |
| status   | enum('active','inactive','deleted') | NO   |     | active  |                |
+----------+-------------------------------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

mysql> 


    3.配置远程用户授权访问
CREATE USER IF NOT EXISTS admin IDENTIFIED WITH mysql_native_password BY 'yinzhengjie';
GRANT ALL ON yinzhengjie.* TO admin;




    4.查看权限验证
mysql> SHOW GRANTS FOR 'admin';
+--------------------------------------------------------+
| Grants for admin@%                                     |
+--------------------------------------------------------+
| GRANT USAGE ON *.* TO `admin`@`%`                      |
| GRANT ALL PRIVILEGES ON `yinzhengjie`.* TO `admin`@`%` |
+--------------------------------------------------------+
2 rows in set (0.00 sec)

mysql> 


    5.访问测试
[root@yinzhengjie ~]# mysql -uadmin -pyinzhengjie -h 10.0.0.20 -e 'SHOW DATABASES;'
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database           |
+--------------------+
| information_schema |
| yinzhengjie        |
+--------------------+
[root@yinzhengjie ~]#

3.连接数据库创建表

package main

import (
    "fmt"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

type UserInfo struct {
    /**
    json:"id"
        在json格式解析时字段名称为id。
    grom:"primary_key"
        对于grom框架而言,声明该字段为主键。

    */
    Id       int64 `json:"id" grom:"primary_key"`
    Username string
    Password string
}

func main() {
    // 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
    dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        fmt.Printf("连接数据库出错: %v\n", err)
        panic(err) // 如果连接出错,就直接抛出异常!
    }

    fmt.Printf("数据库连接成功: %v\n", db)

    /**
    使用AutoMigrate自动创建表结构.

    参考连接:
        https://gorm.io/zh_CN/docs/migration.html

    这个语句慎用,因为其创建的表的数据类型可能比我们预期要给的大:
        mysql> desc user_infos;
        +----------+----------+------+-----+---------+----------------+
        | Field    | Type     | Null | Key | Default | Extra          |
        +----------+----------+------+-----+---------+----------------+
        | id       | bigint   | NO   | PRI | NULL    | auto_increment |
        | username | longtext | YES  |     | NULL    |                |
        | password | longtext | YES  |     | NULL    |                |
        +----------+----------+------+-----+---------+----------------+
        3 rows in set (0.00 sec)

        mysql>
    */
    err = db.AutoMigrate(UserInfo{})
    if err != nil {
        panic(fmt.Sprintf("表创建失败,%v\n", err))
    }
    fmt.Println("数据表创建成功!")

}

4.单表的增删改查

package main

import (
    "fmt"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

type UserInfo struct {
    Id       int64 `json:"id" grom:"primary_key"`
    Username string
    Password string
}

func main() {
    dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        fmt.Printf("连接数据库出错: %v\n", err)
        panic(err) // 如果连接出错,就直接抛出异常!
    }

    err = db.AutoMigrate(UserInfo{})

    // 1.向数据库添加数据,注意多次执行会创建多个用户哟,而且会自动基于ID自增,小心造成数据的重复创建哟!
    db.Create(&UserInfo{
        Username: "JasonYin",
        Password: "yinzhengjie",
    })

    db.Create(&UserInfo{
        Username: "root",
        Password: "yinzhengjie",
    })

    db.Create(&UserInfo{
        Username: "root",
        Password: "123",
    })

    // 2.修改表中的某一个字段
    db.Model(UserInfo{
        Id: 1,
    }).Update("password", "123")

    // 4. 过滤查询数据单条数据
    u1 := UserInfo{Username: "root"}
    db.Where("username= ?", u1.Username).First(&u1)
    fmt.Printf("u1 ---> %#v\n", u1)

    // 5. 过滤查询数据多条数据
    u2 := UserInfo{Username: "root"}
    u2_all_user := []UserInfo{}
    db.Where("username= ?", u2.Username).Find(&u2_all_user)
    fmt.Printf("u2---> %#v\n", u2_all_user)

    // 6.查看所有数据
    users := []UserInfo{} // 定义一个UserInfo结构体切片来接收数据
    db.Find(&users)
    fmt.Printf("all ---> %#v\n", users)

    // 7.删除数据
    // 7.1 基于主键id删除,比如删除id为1的数据
    db.Delete(&UserInfo{Id: 1})
    // 7.2 基于条件删除,比如基于username为root的数据进行删除
    db.Where("username =?", "root").Delete(&UserInfo{})
}

5.数据库的模型定义

package main

import (
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "time"
)

type User struct {
    /**
    声明 model时,tag是可选的,GORM支持以下tag。
        column:
            指定db列名
        type:
            列数据类型,推荐使用兼容性好的通用类型,
            例如:所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用,
            例如:not null、size, autoIncrement… 像 varbinary(8) 这样指定数据库数据类型也是支持的。
            在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:MEDIUMINT UNSIGNED not NULL AUTO_INCREMENT
        serializer:
            指定将数据序列化或反序列化到数据库中的序列化器, 例如: serializer:json/gob/unixtime
        size:
            定义列数据类型的大小或长度,例如 size: 256
        primaryKey:
            将列定义为主键
        unique:
            将列定义为唯一键
        default:
            定义列的默认值
        precision:
            指定列的精度
        scale:
            指定列大小
        not null:
            指定列为NOT NULL
        autoIncrement:
            指定列为自动增长
        autoIncrementIncrement:
            自动步长,控制连续记录之间的间隔
        embedded:
            嵌套字段
        embeddedPrefix:
            嵌入字段的列名前缀
        autoCreateTime:
            创建时追踪当前时间,对于 int 字段,它会追踪时间戳秒数,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoCreateTime:nano
        autoUpdateTime:
            创建/更新时追踪当前时间,对于 int 字段,它会追踪时间戳秒数,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoUpdateTime:milli
        index:
            根据参数创建索引,多个字段使用相同的名称则创建复合索引,查看 索引 获取详情
        uniqueIndex:
            与 index 相同,但创建的是唯一索引
        check:
            创建检查约束,例如 check:age > 13,查看 约束 获取详情
        <-:
            设置字段写入的权限, <-:create 只创建、<-:update 只更新、<-:false 无写入权限、<- 创建和更新权限
        ->:
            设置字段读的权限,->:false 无读权限
        -:
            忽略该字段,- 表示无读写,-:migration 表示无迁移权限,-:all 表示无读写迁移权限
        comment:
            迁移时为字段添加注释

    tag名大小写不敏感,但建议使用camelCase风格。

    更多资料请参考官网:
        https://gorm.io/zh_CN/docs/models.html
    */
    Id           int64      `gorm:"primary_key" json:"id"`
    Name         string     // 默认字符串对应的是数据库的longtext文本类型
    CreatedAt    *time.Time `json:"createdAt" gorm:"column:create_at"`
    Email        string     `gorm:"type:varchar(255);unique_index"` // 使用type字段定义类型,并设置为唯一索引
    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:"-"`                              // 忽略这个字段
}

func main() {
    dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
    db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})

    // 创建表
    err := db.AutoMigrate(User{})
    if err != nil {
        panic(err)
    }
}

三.一对多关联查询

1.has many 一对多概述

has many关联就是创建一个和另一个模型的一对多关系。

例如: 每一个用户都有多张信用卡,这样就是生活中一个简单的一对多关系。


定义关系:
type User struct {
    // gorm.Model是gorm内置的模块,已经定义好了相关的结构体咱们可以直接引用
    gorm.Model
    CreditCard []CreditCard
}

type CreditCard struct {
    gorm.Model
    Number string
    // 默认会在CreditCard表中生成UserID字段作为User表关联的外键ID
    UserID uint
}



推荐阅读:
    https://gorm.io/zh_CN/docs/has_many.html

2.外键

- 为了定义一对多关系, 外键是必须存在的,默认外键的名字是 所有者类型的名字加上它的主键

- 就像上面的例子,为了定义一个属于User的模型,外键就应该为UserID 。

- 使用其他的字段名作为外键, 你可以通过"foreignkey"来定制它,


举个例子:
type User struct {
    gorm.Model
    CreditCard []CreditCard `gorm:"foreignkey:UserRef"`
}

type CreditCard struct {
    gorm.Model
    Number  string
    UserRef uint
}

3.外键关联

- GORM通常使用拥有者的主键作为外键的值。 对于上面的例子,它是User的ID字段。
- 为user添加creditcard 时,GORM 会将user的ID字段保存到creditcard的UserID 字段。
- 同样的,您也可以使用标签 references 来更改它。


举个例子:
type User struct {
    gorm.Model
    MemberNumber string
    CreditCards  []CreditCard `gorm:"foreignKey:UserNumber;references:MemberNumber"`
}

type CreditCard struct {
    gorm.Model
    Number     string
    UserNumber string
}

4.外键约束

你可以通过为标签 constraint 配置 OnUpdate、OnDelete 实现外键约束,在使用 GORM 进行迁移时它会被创建.

举个例子:
type User struct {
  gorm.Model
  CreditCards []CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}

type CreditCard struct {
  gorm.Model
  Number string
  UserID uint
}

5.一对多案例

package main

import (
    "fmt"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

// 2.建立一对多关系
type User struct {
    gorm.Model
    Username string `json:"username gorm:"column:username"`
    // 添加外键关联,只要该字段是一个CreditCard的切片,会自动和CreditCard模型建立外键关联。
    CreditCards []CreditCard
}

type CreditCard struct {
    gorm.Model
    Number string
    // 这个就是User表关联的外键,表示基于User表的ID主键(primary key)字段进行关联。这个是gorm的规定【结构体 + 主键】
    UserID uint
}

func main() {
    // 1.创建gorm的链接
    dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
    db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    fmt.Println(db)

    // 3.创建表结构
    //db.AutoMigrate(User{}, CreditCard{})

    /**
    4.创建一对多

    创建后记得查看数据库信息:
    mysql> SHOW TABLES;
    +-----------------------+
    | Tables_in_yinzhengjie |
    +-----------------------+
    | credit_cards          |
    | users                 |
    +-----------------------+
    2 rows in set (0.00 sec)

    mysql>
    mysql> SELECT * FROM users;
    +----+-------------------------+-------------------------+------------+-----------+
    | id | created_at              | updated_at              | deleted_at | username  |
    +----+-------------------------+-------------------------+------------+-----------+
    |  1 | 2023-11-20 23:48:17.561 | 2023-11-20 23:48:17.561 | NULL       | Jason Yin |
    +----+-------------------------+-------------------------+------------+-----------+
    1 row in set (0.01 sec)

    mysql>
    mysql> SELECT * FROM credit_cards;
    +----+-------------------------+-------------------------+------------+--------+---------+
    | id | created_at              | updated_at              | deleted_at | number | user_id |
    +----+-------------------------+-------------------------+------------+--------+---------+
    |  1 | 2023-11-20 23:48:17.574 | 2023-11-20 23:48:17.574 | NULL       | 1001   |       1 |
    |  2 | 2023-11-20 23:48:17.574 | 2023-11-20 23:48:17.574 | NULL       | 1002   |       1 |
    +----+-------------------------+-------------------------+------------+--------+---------+
    2 rows in set (0.00 sec)

    mysql>

    */
    //user := User{
    //    Username: "Jason Yin",
    //    CreditCards: []CreditCard{
    //        {Number: "1001"},
    //        {Number: "1002"},
    //    },
    //}
    //
    //db.Create(&user)

    // 5.为已存在的用户添加信用卡
    u := User{
        Username: "Jason Yin",
    }
    db.First(&u) // 查找返回的第一条记录

    // 使用Association方法基于指定"CreditCards"关联外键字段找到关联关系,并使用Append方法追加信息。
    db.Model(&u).Association("CreditCards").Append([]CreditCard{
        {Number: "1003"},
        {Number: "1004"},
    })

    /**
        添加成功后,再次查看表信息


        mysql> SHOW TABLES;
        +-----------------------+
        | Tables_in_yinzhengjie |
        +-----------------------+
        | credit_cards          |
        | users                 |
        +-----------------------+
        2 rows in set (0.00 sec)

        mysql>
        mysql> SELECT * FROM users;
        +----+-------------------------+-------------------------+------------+-----------+
        | id | created_at              | updated_at              | deleted_at | username  |
        +----+-------------------------+-------------------------+------------+-----------+
        |  1 | 2023-11-20 23:48:17.561 | 2023-11-21 00:00:12.988 | NULL       | Jason Yin |
        +----+-------------------------+-------------------------+------------+-----------+
        1 row in set (0.00 sec)

        mysql>
        mysql> SELECT * FROM credit_cards;
        +----+-------------------------+-------------------------+------------+--------+---------+
        | id | created_at              | updated_at              | deleted_at | number | user_id |
        +----+-------------------------+-------------------------+------------+--------+---------+
        |  1 | 2023-11-20 23:48:17.574 | 2023-11-20 23:48:17.574 | NULL       | 1001   |       1 |
        |  2 | 2023-11-20 23:48:17.574 | 2023-11-20 23:48:17.574 | NULL       | 1002   |       1 |
        |  3 | 2023-11-21 00:00:12.991 | 2023-11-21 00:00:12.991 | NULL       | 1003   |       1 |
        |  4 | 2023-11-21 00:00:12.991 | 2023-11-21 00:00:12.991 | NULL       | 1004   |       1 |
        +----+-------------------------+-------------------------+------------+--------+---------+
        4 rows in set (0.00 sec)

        mysql>

    */
}

6.一对多Association关联查询【不推荐】

package main

import (
    "encoding/json"
    "fmt"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

// 2.建立一对多关系
type User struct {
    gorm.Model
    Username string `json:"username gorm:"column:username"`
    // 添加外键关联,只要该字段是一个CreditCard的切片,会自动和CreditCard模型建立外键关联。
    CreditCards []CreditCard
}

type CreditCard struct {
    gorm.Model
    Number string
    // 这个就是User表关联的外键,表示基于User表的ID主键(primary key)字段进行关联。
    UserID uint
}

func main() {
    // 1.创建gorm的链接
    dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
    db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    fmt.Println(db)

    /**
    3.查询关联表数据

    使用Association方法:
        1)需要把User查询好;
        2)然后根据User定义中指定的AssociationForeignKey去查找CreditCard;

    这种查询方式需要使用2次回表查询,效率会很低,慎用!!!

    官方链接:
        https://gorm.io/zh_CN/docs/associations.html#%E6%9F%A5%E6%89%BE%E5%85%B3%E8%81%94
    */

    // 3.1 先查询User表数据
    u := User{Username: "Jason Yin"}
    db.First(&u)
    //fmt.Printf("%v\n", u.Username)

    // 3.2 基于AssociationForeignKey外键字段"CreditCards"进行查找
    err := db.Model(&u).Association("CreditCards").Find(&u.CreditCards)
    if err != nil {
        panic(fmt.Sprintf("err ---> %v\n", err))
    }

    // 将其转换为json格式显示
    bytes, _ := json.Marshal(&u)
    fmt.Println(string(bytes))
}

7.一对多Preload预加载关联查询【推荐】

package main

import (
    "encoding/json"
    "fmt"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

// 2.建立一对多关系
type User struct {
    gorm.Model
    Username string `json:"username gorm:"column:username"`
    // 添加外键关联,只要该字段是一个CreditCard的切片,会自动和CreditCard模型建立外键关联。
    CreditCards []CreditCard
}

type CreditCard struct {
    gorm.Model
    Number string
    // 这个就是User表关联的外键,表示基于User表的ID主键(primary key)字段进行关联。
    UserID uint
}

func main() {
    // 1.创建gorm的链接
    dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
    db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    fmt.Println(db)

    /**
    3.使用Preload预加载方法:
        在查询User时先去获取CreditCard的记录

    很明显,这种效率会更高,一次性把数据查询出来,不会去回表查询两次。

    推荐阅读:
        https://gorm.io/zh_CN/docs/preload.html
    */
    users := []User{}
    db.Preload("CreditCards").Find(&users)

    bytesUser, _ := json.Marshal(&users)
    fmt.Println(string(bytesUser))
}

四.多对多关联查询

1.对多对关系描述

Many to Many会在两个model中添加一张连接表。

举个例子:
    一个学生可以选择多个课程,一个课程又包含多个学生,这是双向对对多的关系。

推荐阅读:
    https://gorm.io/zh_CN/docs/many_to_many.html

2.多对多表结构创建

package main

import (
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

// 2.定义多对多关联表
type User struct {
    gorm.Model
    /**
    gorm:"many2many:user_languages;"
        指定了User表和Language表是多对多的关系,且"user_languages"是第三张连接表。
    */
    Languages []Language `gorm:"many2many:user_languages;"`
}

type Language struct {
    gorm.Model
    Name string
}

func main() {
    // 1.创建gorm的链接
    dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
    db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})

    /**
    3.创建多对多表结构

    创建成功后记得去数据库验证多对多表结构创建信息:
    mysql> SHOW TABLES;
    +-----------------------+
    | Tables_in_yinzhengjie |
    +-----------------------+
    | languages             |
    | user_languages        |
    | users                 |
    +-----------------------+
    3 rows in set (0.00 sec)

    mysql>
    mysql> DESC users;
    +------------+-----------------+------+-----+---------+----------------+
    | Field      | Type            | Null | Key | Default | Extra          |
    +------------+-----------------+------+-----+---------+----------------+
    | id         | bigint unsigned | NO   | PRI | NULL    | auto_increment |
    | created_at | datetime(3)     | YES  |     | NULL    |                |
    | updated_at | datetime(3)     | YES  |     | NULL    |                |
    | deleted_at | datetime(3)     | YES  | MUL | NULL    |                |
    +------------+-----------------+------+-----+---------+----------------+
    4 rows in set (0.01 sec)

    mysql>
    mysql> DESC languages;
    +------------+-----------------+------+-----+---------+----------------+
    | Field      | Type            | Null | Key | Default | Extra          |
    +------------+-----------------+------+-----+---------+----------------+
    | id         | bigint unsigned | NO   | PRI | NULL    | auto_increment |
    | created_at | datetime(3)     | YES  |     | NULL    |                |
    | updated_at | datetime(3)     | YES  |     | NULL    |                |
    | deleted_at | datetime(3)     | YES  | MUL | NULL    |                |
    | name       | longtext        | YES  |     | NULL    |                |
    +------------+-----------------+------+-----+---------+----------------+
    5 rows in set (0.00 sec)

    mysql>
    mysql> DESC user_languages;
    +-------------+-----------------+------+-----+---------+-------+
    | Field       | Type            | Null | Key | Default | Extra |
    +-------------+-----------------+------+-----+---------+-------+
    | user_id     | bigint unsigned | NO   | PRI | NULL    |       |
    | language_id | bigint unsigned | NO   | PRI | NULL    |       |
    +-------------+-----------------+------+-----+---------+-------+
    2 rows in set (0.00 sec)

    mysql>
    */
    db.AutoMigrate(User{}, Language{})
}

3.多对多表结构自定义连接表

package main

import (
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "time"
)

// 2.定义多对多关联表
type Person struct {
    ID   int
    Name string
    // 声明对对多关系,让Person和Address表进行关联
    Addresses []Address `gorm:"many2many:person_addresses;"`
}

type Address struct {
    ID   uint
    Name string
}

// 自定义第三张表时我们除了可以关联两个表的关联字段外,还可以添加一些我们需要的字段,比如"CreatedAt",”DeletedAt“等。
type PersonAddresses struct {
    // 对应Person表的主见
    PersonID int `gorm:"primaryKey"`
    // 对应Address表的主见
    AddressID int `gorm:"primaryKey"`
    CreatedAt time.Time
    DeletedAt gorm.DeletedAt
}

func main() {
    // 1.创建gorm的链接
    dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
    db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})

    // 3.创建第三张表
    db.AutoMigrate(Person{}, Address{}, PersonAddresses{})

    /**
    4.添加数据

    进入数据库终端查询结构如下:
    mysql> SHOW TABLES;
    +-----------------------+
    | Tables_in_yinzhengjie |
    +-----------------------+
    | addresses             |
    | people                |
    | person_addresses      |
    +-----------------------+
    3 rows in set (0.00 sec)

    mysql> SELECT * FROM people;
    +----+-----------+
    | id | name      |
    +----+-----------+
    |  1 | Jason Yin |
    |  2 | 尹正杰    |
    +----+-----------+
    2 rows in set (0.00 sec)

    mysql> SELECT * FROM addresses;
    +----+-----------+
    | id | name      |
    +----+-----------+
    |  1 | 北京      |
    |  2 | 上海      |
    |  3 | 深圳      |
    |  4 | 陕西      |
    |  5 | 河北      |
    |  6 | 山东      |
    |  7 | 黑龙江    |
    +----+-----------+
    7 rows in set (0.00 sec)

    mysql> SELECT * FROM person_addresses;
    +-----------+------------+------------+------------+
    | person_id | address_id | created_at | deleted_at |
    +-----------+------------+------------+------------+
    |         1 |          1 | NULL       | NULL       |
    |         1 |          2 | NULL       | NULL       |
    |         1 |          3 | NULL       | NULL       |
    |         2 |          4 | NULL       | NULL       |
    |         2 |          5 | NULL       | NULL       |
    |         2 |          6 | NULL       | NULL       |
    |         2 |          7 | NULL       | NULL       |
    +-----------+------------+------------+------------+
    7 rows in set (0.00 sec)

    mysql>

    */
    p1 := Person{
        ID:   1,
        Name: "Jason Yin",
        Addresses: []Address{
            {ID: 1, Name: "北京"},
            {ID: 2, Name: "上海"},
            {ID: 3, Name: "深圳"},
        },
    }

    p2 := Person{
        ID:   2,
        Name: "尹正杰",
        Addresses: []Address{
            {ID: 4, Name: "陕西"},
            {ID: 5, Name: "河北"},
            {ID: 6, Name: "山东"},
            {ID: 7, Name: "黑龙江"},
        },
    }
    db.Create(&p1)
    db.Create(&p2)

}

4.多对多Preload预加载

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() {
    // 1.创建gorm的链接
    dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
    db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})

    // 1.获取所有用户的地址
    persons := []Person{}
    db.Preload("Addresses").Find(&persons)
    allData, _ := json.Marshal(&persons)
    fmt.Println(string(allData))

    // 2.获取 name="Jason Yin" 用户的地址
    person := Person{Name: "Jason Yin"}
    db.Preload("Addresses").Find(&person)
    oneData, _ := json.Marshal(&person)
    fmt.Println(string(oneData))

}
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
安全 Go
Golang 语言是面向对象编程风格的编程语言吗?
Golang 语言是面向对象编程风格的编程语言吗?
47 0
|
6月前
|
关系型数据库 MySQL Go
golang使用gorm操作mysql1
golang使用gorm操作mysql1
golang使用gorm操作mysql1
|
6月前
|
Go
golang使用gorm操作mysql3,数据查询
golang使用gorm操作mysql3,数据查询
|
6月前
|
JSON 前端开发 Java
golang使用gorm操作mysql2
golang使用gorm操作mysql2
|
6月前
|
缓存 Cloud Native 测试技术
Golang 乐观锁实战:Gorm 乐观锁的优雅使用
在现代软件开发中,数据一致性是一个永恒的话题。随着系统规模的扩大和并发操作的增加,如何有效地处理并发冲突,确保数据的完整性,成为了开发者必须面对的挑战。本文将带你深入了解 Golang 中 Gorm ORM 库的乐观锁机制,并通过实际示例,展示如何在项目中优雅地使用乐观锁。
|
缓存 NoSQL 中间件
用golang搭建springboot风格项目结构 gin+gorm
最近学了学go语言,想练习一下用go开发web项目,项目结构弄个什么样呢。
|
Java Go C语言
100天精通Golang(基础入门篇)——第2天:学习Go语言的前世今生:一门强大的编程语言的崛起
100天精通Golang(基础入门篇)——第2天:学习Go语言的前世今生:一门强大的编程语言的崛起
219 1
|
12月前
|
SQL 关系型数据库 Go
Golang微服框架Kratos与它的小伙伴系列 - ORM框架 - GORM
[GORM](https://gorm.io/index.html) 是基于Go语言实现的ORM库,它是Golang目前比较热门的数据库ORM操作库,对开发者也比较友好,使用非常方便简单。
134 0
|
SQL 存储 关系型数据库
开源 Golang 微服务入门三:ORM 框架 GORM| 青训营笔记
GORM 是面向 Golang 语言的一种 ORM(持久层)框架,支持多种数据库的接入,此框架弱化了开发者对于 SQL 语言的掌握程度,使用提供的 API 进行底层数据库的访问。使用提供的 API 进
150 0
开源 Golang 微服务入门三:ORM 框架 GORM| 青训营笔记
|
Go 数据库
Golang:gorm的常用CRUD操作
Golang:gorm的常用CRUD操作
203 0
Golang:gorm的常用CRUD操作