Gorm入门,带你实现简单的增删改查|青训营

252 阅读6分钟

Gorm

什么是orm?

Object-Relationl Mapping,即对象关系映射,这里的Relationl指的是关系型数据库

它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了 。

为什么选择GORM

  • 全功能 ORM
  • 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
  • Create,Save,Update,Delete,Find 中钩子方法
  • 支持 Preload、Joins 的预加载
  • 事务,嵌套事务,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…
  • 每个特性都经过了测试的重重考验
  • 开发者友好

官方文档

gorm.book.jasperxu.com/ 利用官方文档可以帮你更全面的掌握gorm的知识

如何使用Gorm

在go编译器的终端中运行以下代码

## 必须安装gorm
go get -u gorm.io/gorm     
## 安装相应的数据库驱动。GORM 官方支持的数据库类型有: MySQL, PostgreSQL, SQlite, SQL Server
go get -u gorm.io/driver/mysql  

连接到Mysql数据库

package main

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

func main() {
	// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
	//dsn := "username:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
	//db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	db, err := gorm.Open(mysql.New(mysql.Config{
		DSN:                       "root:123456@tcp(192.168.168.101:3306)/gorm?charset=utf8&parseTime=True&loc=Local", // DSN data source name
		DefaultStringSize:         256,                                                                                // string 类型字段的默认长度
		DisableDatetimePrecision:  true,                                                                               // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
		DontSupportRenameIndex:    true,                                                                               // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
		DontSupportRenameColumn:   true,                                                                               // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
		SkipInitializeWithVersion: false,                                                                              // 根据当前 MySQL 版本自动配置
	}), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}
	// ----------------------------数据库连接池----------------------------
	sqlDB, err := db.DB()
	// SetMaxIdleConns 设置空闲连接池中连接的最大数量
	sqlDB.SetMaxIdleConns(10)
	// SetMaxOpenConns 设置打开数据库连接的最大数量。
	sqlDB.SetMaxOpenConns(100)
	// SetConnMaxLifetime 设置了连接可复用的最大时间。
	sqlDB.SetConnMaxLifetime(time.Hour)
	fmt.Println("success to link mysql")
	select {}
}

简易版本

package main

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

func main() {
	// 用户名:密码@tcp(ip:port)/数据库?charset=utf8mb4&parseTime=True&loc=Local
	dsn := "root:root123@tcp(127.0.0.1:3306)/test_gorm?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic(err)
	}

}


约定 > 配置 > 编码

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

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

Gorm默认使用Id作为主键

type User struct { 
    ID  string // 默认情况下,名为 `ID` 的字段会作为表的主键 
    Name string
}

GORM 默认使用结构体名的 snake case 复数作为表名

eg:结构体 userinfo,其表名默认为user_infos

蛇形命名法(snake case)类似 驼峰命名法(camel case) ,都是要克服单词间的空格,从而把不同单词串连起来,最终达到创造出一种新的单词的效果。

临时指定表名

// 根据 User 的字段创建 `deleted_users` 表
db.Table("deleted_users").AutoMigrate(&User{})

// 从另一张表查询数据
var deletedUsers []User
db.Table("deleted_users").Find(&deletedUsers)
// SELECT * FROM deleted_users;

db.Table("deleted_users").Where("name = ?", "jinzhu").Delete(&User{})
// DELETE FROM deleted_users WHERE name = 'jinzhu';

也可以在声明模型的同时指定表明

type User struct{
    username string,
    password string
}
//返回你要查询的表名
func(User) TableName string{
   return "users"
}

tag标签【重点】

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

标签名说明
column指定 db 表列名
type列数据类型,推荐使用兼容性好的通用类型
serializer指定如何序列化/反序列化到数据库, e.g: serializer:json/gob/unixtime
size指定列的数据大小/长度, e.g: size:256
primaryKey指定列作为主键
unique指定列唯一
default指定列为默认值
precision指定列的精度
scalespecifies column scale
not null指定列 NOT NULL
autoIncrement指定列为自增列
autoIncrementIncrementauto increment step, controls the interval between successive columnvalues
embedded嵌入字段
embeddedPrefix嵌入字段的列名前缀
autoCreateTime记录创建时间
autoUpdateTime记录创建/更新时间
index根据选项创建索引
uniqueIndex唯一索引
check创建检查约束, eg: check:age > 13, refer Constraints
<-设置字段的写权限
<-:create create-only field,
<-:update update-only field,
<-:false no write permission,
<-create and update permission
->设置字段读权限
->:false no read permission
-忽略当前字段
-no read/write permission,
-:migration no migrate permission,
-:all no read/write/migrate permission
comment【迁移时】为字段添加注释

高级选项

字段权限

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

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
}

创建、更新时间

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

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

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

嵌入结构体

可以通过标签 embedded 将一个结构体嵌入另一个结构体。可以使用标签 embeddedPrefix 来为 db 中的字段名添加前缀

type Author struct {
    Name  string
    Email string
}

type Blog struct {
  ID      int
  Author  Author `gorm:"embedded;embeddedPrefix:author_"`
  Upvotes int32
}
// 等效于
type Blog struct {
  ID          int64
    AuthorName  string
    AuthorEmail string
  Upvotes     int32
}

CRUD

入门案例

这是一个简易的gorm程序,支持简单的增删改查,如果你是初学者,可以试着来感受下gorm的数据操作,后面的知识是gorm支持的复杂的操作

package main

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

type User struct {
	Id   int
	Name string
	Age  int
	Addr string
	Pic  string
}

func main() {
//这里参考上文将配置换成你自己的数据库信息
	dsn := "root:root@tcp(127.0.0.1:3306)/test_gorm?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic(err)
	}
	// 自动迁移
	db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&User{})

	// 增
	db.Create(&User{
		Name: "张三",
		Age:  18,
		Addr: "北京市",
		Pic:  "/static/img.png",
	})

	// 查
	var user User
	db.First(&user)
	fmt.Println(user) // {1 张三 18 北京市 /static/img.png}

	// 改
	user.Name = "lisi"
	db.Save(&user)
	fmt.Println(user) // {1 lisi 18 北京市 /static/img.png}

	// 删
	db.Delete(&user)
}