day12 玩转CRUD|青训营笔记

137 阅读5分钟

题记

这是我参与「第五届青训营 」伴学笔记创作活动的第 12天,本文用于记录在青训营的学习笔记和一些心得。

day12 1月26日

本节课主要有四个内容:

  • 课程介绍
  • 三件套的使用
  • 实战案例介绍
  • 课程总结

课程介绍

本节课主要有三个目标:

  • 将前面几节课所学到的知识应用到项目中。
  • 掌握Hertz、KiteX、Gorm的基本用法。
  • 通过学习实战案例,可以使用Hertz、KiteX、Gorm完成日常后端开发任务

三件套的介绍

image-20230126152534775

Gorm

命名
type Product struct {
   Code string
   Price uint
}
​
func (p Product) TableName() string {
   return "product"
}

Gorm的约定(默认规则):

  • Gorm使用名为ID的字段作为主键
  • 使用结构体的蛇形复数作为表名(如上面的代码,本来表名应该是products,因为Gorm提供了TableName方法,你可以自动给表命名)
  • 字段名的蛇形作为列名
  • 使用CreatedAt, UpdatedAt字段作为创建、更新时间。
  • GORM内置了一个gorm.Model结构体。gorm.Model是一个包含了ID, CreatedAt, UpdatedAt, DeletedAt四个字段的Golang结构体。
数据库连接

Gorm目前支持MySQL,SQLServer,PostgreSQL,SQLite。

Gorm通过驱动来连接数据库,如果需要连接其他类型的数据库,可以复用/自动开发驱动。

DSN:Data Source Name (DSN)的PDO命名惯例为:PDO驱动程序的名称,后面为一个冒号,再后面是可选的驱动程序连接数据库变量信息,如主机名、端口和数据库名。

import (
  "gorm.io/driver/mysql"
  "gorm.io/gorm"
)
​
func main() {
  dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
  db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
}

dsn中要传入username(一般是root)和password,然后是数据库名称,字符集的设置,时区的设置。ParseTime为true:time.time才能有用。

创建

image-20230126163517719

image-20230126163530716

ID    uint   `gorm:"primaryKey"`   //创建主键
Code  string `gorm:"column:code"`  //列名命名为code
Price uint   `gorm:"column:user_id"` //列名命名为user_id
​
Age int64 `gorm:"default:18"`  //年龄设置默认值18
Name string `gorm:"default:xxx"`  //姓名设置默认值xxx

db.AutoMigrate(&Product{}):GORM 的 AutoMigrate() 方法用于自动迁移 ORM 的 Schemas。所谓 “迁移” 就是刷新数据库中的表格定义,使其保持最新(只增不减)。AutoMigrate 会创建(新的)表、缺少的外键、约束、列和索引,并且会更改现有列的类型(如果其大小、精度、是否为空可更改的话)。但不会删除未使用的列,以保护现存的数据。

创建记录一定要地址传入,多条记录创建使用切片。

查询

image-20230126175507470

users是一个存储查询结果的容器。

这个是数据库记录,用于测试用的。

image-20230126175627220

这个是代码的执行结果

image-20230126175721106

First的使用踩坑:使用 First时,需要注意查询不到数据会返回ErrRecordNotFound。

使用Find查询多条数据,查询不到数据不会返回错误。

使用结构体作为查询条件:当使用结构作为条件查询时,GORM只会查询非零值字段。这意味着如果您的字段值为0、"、false或其他零值,该字段不会被用于构建查询条件,使用Map来构建查询条件。

更新

image-20230126202225337

Omit和select刚好相反是省略的功能。

注意更新一个列用update,多个列用updates。

使用Struct 更新时,只会更新非零值,如果需要更新零值可以使用 Map更新或使用Select选择字段。

删除

image-20230126204655955

image-20230126210252131

GORM提供了gorm.DeletedAt用于帮助用户实现软删。

拥有软删除能力的Model调用Delete时,记录不会被从数据库中真正删除。但 GORM会将DeletedAt置为当前时间,并且你不能再通过正常的查询方法找到该记录。

使用Unscoped可以查询到被软删的数据。

事务

Gorm提供了Begin,Commit,Rollback方法用于使用事务。

image-20230126210943526

Tansaction方法用于自动提交事务,避免用户漏写Commit和Rollback。

image-20230126211416381

Hook

GORM在提供了CURD的Hook能力。

Hook是在创建、查询、更新、删除等操作之前、之后自动调用的函数。

如果任何Hook返回错误,GORM将停止后续的操作并回滚事务。创建钩子

GORM 允许用户定义的钩子有 BeforeSave, BeforeCreate, AfterSave, AfterCreate 创建记录时将调用这些钩子方法。

func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
  u.UUID = uuid.New()
​
    if u.Role == "admin" {
        return errors.New("invalid role")
    }
    return
}

首先u.UUID = uuid.New()查了下资料:

  • uuid是Universally Unique Identifier的缩写,即通用唯一识别码。uuid的目的是让分布式系统中的所有元素,都能有唯一的辨识资讯,而不需要透过中央控制端来做辨识资讯的指定。如此一来,每个人都可以建立不与其它人冲突的 uuid。A universally unique identifier (UUID) is a 128-bit number used to identify information in computer systems.
  • 想调用uuid 需要go get -u github.com/satori/go.uuid。

其次该函数只需声明,不用调用,当想要的表执行相应操作,该钩子会自己执行。

如果您想跳过 钩子 方法,您可以使用 SkipHooks 会话模式,例如:

DB.Session(&gorm.Session{SkipHooks: true}).Create(&user)
DB.Session(&gorm.Session{SkipHooks: true}).Create(&users)
DB.Session(&gorm.Session{SkipHooks: true}).CreateInBatches(users, 100)

image-20230125210153411

性能提高

对于写操作(创建、更新、删除),为了确保数据的完整性,Gorm会将它们封装在事务内运行。但这会降低性能,你可以使用SkipDefaultTransaction关闭默认事务。

使用PrepareStmt缓存预编译语句可以提高后续调用的速度,本机测试提高大约35%左右。

image-20230126211951942

生态

image-20230126212009381