• Go语言学习笔记—gorm(一)



    一 gorm概述

    1.1 ORM简介

    对象关系映射(Object-Relationl Mapping,简称ORM)模式是一种为了解决面向对象和关系数据库(如mysql数据库)存在的互相不匹配的现象的技术。简单来说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。

    1.2 官方文档

    https://gorm.io/zh_CN/docs/
    
    • 1

    1.3 gorm特性

    • 全功能 ORM
    • 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
    • Create,Save,Update,Delete,Find 中钩子方法
    • 支持 PreloadJoins 的预加载
    • 事务,嵌套事务,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.4 安装

    go get -u gorm.io/gorm
    go get -u gorm.io/driver/mysql
    
    • 1
    • 2

    1.5 快速入门

    package main
    
    import (
    	"gorm.io/driver/mysql"
    	"gorm.io/gorm"
    )
    
    type Product struct {
    	gorm.Model
    	Code  string
    	Price uint
    }
    
    func main() {
    	dsn := "root:960690@tcp(127.0.0.1:3306)/golang_db??charset=utf8mb4&parseTime=True&loc=Local"
    	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    	if err != nil {
    		panic("failed to connect database")
    	}
    
    	// 创建表
    	db.AutoMigrate(&Product{})
    
    	// 插入数据
    	db.Create(&Product{Code: "666", Price: 100})
    
    	// 查询数据
    	var product Product
    	db.First(&product, 1)                 // 根据整型主键查找
    	db.First(&product, "code = ?", "666") // 查找 code 字段值为 666 的记录
    
    	// 更新数据 - 将 product 的 price 更新为 200
    	db.Model(&product).Update("Price", 200)
    	// 更新数据 - 更新多个字段
    	db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // 仅更新非零值字段
    	db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})
    
    	// 删除数据 - 删除 product
    	// 非物理删除,而是添加了删除标记
    	db.Delete(&product, 1)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    二 gorm声明模型

    2.1 模型定义

    模型是标准的 struct,由 Go 的基本数据类型、实现了 Scanner 和 Valuer 接口的自定义类型及其指针或别名组成

    例如:

    type User struct {
      ID           uint
      Name         string
      Email        *string
      Age          uint8
      Birthday     *time.Time
      MemberNumber sql.NullString
      ActivatedAt  sql.NullTime
      CreatedAt    time.Time
      UpdatedAt    time.Time
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.2 约定

    GORM 倾向于约定,而不是配置。默认情况下,GORM 使用 ID 作为主键,使用结构体名的 蛇形复数 作为表名,字段名的 蛇形 作为列名,并使用 CreatedAtUpdatedAt 字段追踪创建、更新时间。

    遵循 GORM 已有的约定,可以减少您的配置和代码量。如果约定不符合您的需求,GORM 允许您自定义配置它们。

    规则:

    • 第一个大写字母变为小写;
    • 遇到其他大写字母变为小写并且在前面加下划线;
    • 连着的几个大写字母,只有第一个遵循上面的两条规则,其他的大写字母转为小写,不加下划线,遇到小写,前面的第一个大写字母变小写并加下划线;
    • 复数形式;

    举例

    • User => users 首字母小写,复数
    • UserInfo => user_infos
    • DBUserInfo => db_user_infos
    • DBXXXXUserInfo => dbxxxx_user_infos

    2.3 gorm.Model

    GORM 定义一个 gorm.Model 结构体,其包括字段 IDCreatedAtUpdatedAtDeletedAt

    // gorm.Model 的定义
    type Model struct {
    	ID        uint `gorm:"primarykey"`
    	CreatedAt time.Time
    	UpdatedAt time.Time
    	DeletedAt DeletedAt `gorm:"index"`
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    您可以将它嵌入到您的结构体中,以包含这几个字段:

    • ID:主键自增长;
    • CreatedAt:用于存储记录的创建时间;
    • UpdatedAt:用于存储记录的修改时间;
    • DeletedAt:用于存储记录的删除时间;

    2.4 高级选项

    2.4.1 字段级权限控制

    可导出的字段在使用 GORM 进行 CRUD 时拥有全部的权限,此外,GORM 允许您用标签控制字段级别的权限。这样您就可以让一个字段的权限是只读、只写、只创建、只更新或者被忽略

    注意: 使用 GORM Migrator 创建表时,不会创建被忽略的字段

    type User struct {
      Name string `gorm:"<-:create"` // allow read and create
      Name string `gorm:"<-:update"` // allow read and update
      Name string `gorm:"<-"`        // allow read and write (create and update)
      Name string `gorm:"<-:false"`  // allow read, disable write permission
      Name string `gorm:"->"`        // readonly (disable write permission unless it configured)
      Name string `gorm:"->;<-:create"` // allow read and create
      Name string `gorm:"->:false;<-:create"` // createonly (disabled read from db)
      Name string `gorm:"-"`            // ignore this field when write and read with struct
      Name string `gorm:"-:all"`        // ignore this field when write, read and migrate with struct
      Name string `gorm:"-:migration"`  // ignore this field when migrate with struct
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.4.2 创建/更新时间追踪(纳秒、毫秒、秒、Time)

    GORM 约定使用 CreatedAtUpdatedAt 追踪创建/更新时间。如果您定义了这种字段,GORM 在创建、更新时会自动填充当前时间

    要使用不同名称的字段,您可以配置 autoCreateTimeautoUpdateTime 标签

    如果您想要保存 UNIX(毫/纳)秒时间戳,而不是 time,您只需简单地将 time.Time 修改为 int 即可

    type User struct {
      CreatedAt time.Time // 在创建时,如果该字段值为零值,则使用当前时间填充
      UpdatedAt int       // 在创建时该字段值为零值或者在更新时,使用当前时间戳秒数填充
      Updated   int64 `gorm:"autoUpdateTime:nano"` // 使用时间戳填纳秒数充更新时间
      Updated   int64 `gorm:"autoUpdateTime:milli"` // 使用时间戳毫秒数填充更新时间
      Created   int64 `gorm:"autoCreateTime"`      // 使用时间戳秒数填充创建时间
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.4.3 嵌入结构体

    对于匿名字段,GORM 会将其字段包含在父结构体中,例如:

    type User struct {
      gorm.Model
      Name string
    }
    // 等效于
    type User struct {
    	ID        uint `gorm:"primarykey"`
    	CreatedAt time.Time
    	UpdatedAt time.Time
    	DeletedAt DeletedAt `gorm:"index"`
    	Name string
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    对于正常的结构体字段,你也可以通过标签 embedded 将其嵌入,例如:

    type Author struct {
        Name   string
        Email  string
    }
    
    type Blog struct {
      ID	   int
      Author	Author `gorm:"embedded"`
      Upvotes	int32
    }
    // 等效于
    type Blog struct {
      ID      int64
      Name     string
      Email    string
      Upvotes   int32
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    并且,您可以使用标签 embeddedPrefix 来为 db 中的字段名添加前缀,例如:

    type Blog struct {
      ID		int
      Author	 Author `gorm:"embedded;embeddedPrefix:author_"`
      Upvotes	 int32
    }
    // 等效于
    type Blog struct {
      ID        int64
      AuthorName   string
      AuthorEmail  string
      Upvotes     int32
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.4.4 字段标签

    声明 model 时,tag 是可选的,GORM 支持以下 tag: tag 名大小写不敏感,但建议使用 camelCase 风格

    标签名说明
    column指定 db 列名
    type列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用,例如:not nullsize, autoIncrement… 像 varbinary(8) 这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:MEDIUMINT UNSIGNED not NULL AUTO_INCREMENT
    serializerspecifies serializer for how to serialize and deserialize data into db, e.g: 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根据参数创建索引,多个字段使用相同的名称则创建复合索引,查看 索引 获取详情
    uniqueIndexindex 相同,但创建的是唯一索引
    check创建检查约束,例如 check:age > 13,查看 约束 获取详情
    <-设置字段写入的权限, <-:create 只创建、<-:update 只更新、<-:false 无写入权限、<- 创建和更新权限
    ->设置字段读的权限,->:false 无读权限
    -忽略该字段,- 无读写权限
    comment迁移时为字段添加注释

    示例:

    type User struct {
      gorm.Model
      Name         string
      Age          sql.NullInt64
      Birthday     *time.Time
      Email        string  `gorm:"type:varchar(100);unique_index"`
      Role         string  `gorm:"size:255"` // 设置字段大小为255
      MemberNumber *string `gorm:"unique;not null"` // 设置会员号(member number)唯一并且不为空
      Num          int     `gorm:"AUTO_INCREMENT"` // 设置 num 为自增类型
      Address      string  `gorm:"index:addr"` // 给address字段创建名为addr的索引
      IgnoreMe     int     `gorm:"-"` // 忽略本字段
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.4.5 关联标签

    GORM 允许通过标签为关联配置外键、约束、many2many 表

    三 gorm连接到MySQL

    import (
      "gorm.io/driver/mysql"
      "gorm.io/gorm"
    )
    
    func main() {
      // 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
      dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
      db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    连接mysql数据库需要按照上面的格式,输入用户名和密码,以及数据库对应IP地址以及端口号,dbname是数据库的名字,charset=utf8mb4支持完整的utf-8编码。

    **注意:**想要正确的处理 time.Time ,您需要带上 parseTime 参数, 要支持完整的 UTF-8 编码,您需要将 charset=utf8 更改为 charset=utf8mb4

  • 相关阅读:
    npm ERR! Cannot read properties of null (reading ‘pickAlgorithm‘)
    thinkPhp5返回某些指定字段
    堆排序算法
    The 2022 ICPC Asia Xian Regional Contest--C. Clone Ranran
    第三十九章 持久对象和SQL - 持久类的 SQL 映射
    python-自动化篇-终极工具-用GUI自动控制键盘和鼠标-pyautogui-键盘
    [附源码]java毕业设计小型银行贷款管理系统
    一个基于C#开发的Excel转Json工具
    JavaScript进阶之路(一)初学者的开始
    JAVA基础(JAVA SE)学习笔记(十)多线程
  • 原文地址:https://blog.csdn.net/qq_39280718/article/details/126302431