GO框架三件套之GORM | 青训营笔记

190 阅读5分钟

这是我参与「第五届青训营 」笔记创作活动的第7天

ORM是什么

对象关系映射技术(ORM,全称object releational mapping),用于解决面向对象和关系数据库存在的不匹配现象的技术

ORM框架:为了解决面向对象和关系数据库存在的不匹配现象的框架

GORM:迭代了10+年的功能强大的ORM框架

RPC是什么

  • IPC:inter-process communication 进程间通讯

IPC有两种方式,一种是LPC(local procedure communication),一种是RPC(remote procedure communication);

  • LPC:本地过程调用,不同的任务使用同一内存区域交换信息

  • RPC:远程过程调用,可以调用某一内存地址的过程或者函数(通常是在同一个网络中的另一台机器上)

Kitex:字节内部的Golang微服务RPC框架

HTTP框架

HTTP:hypter text transfer protocol超文本传输协议,架构在TCP之上;是应用层的协议

hertz:字节内部的http框架

GORM官方文档

gorm.cn/zh_CN/docs

安装GORM方式

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

GORM连接数据库

  • DSN数据格式:[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]
  • 连接数据库代码示例:
import (   
    "gorm.io/driver/mysql"   
    "gorm.io/gorm" 
)  

func main() {   
    // 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情   
    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{})
}
  • 参数是大小写敏感的,更多参数设置参考网站:

go-sql-driver/mysql: Go MySQL Driver is a MySQL driver for Go's (golang) database/sql package (github.com)

  • 连接数据库并执行相关操作的demo代码如下:
package main

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

type Product struct {
	gorm.Model
	Code  string
	Price uint
}

func main() {
	db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	// 迁移 schema
	db.AutoMigrate(&Product{})

	// Create
	db.Create(&Product{Code: "D42", Price: 100})

	// Read
	var product Product
	db.First(&product, 1)                 // 根据整形主键查找
	db.First(&product, "code = ?", "D42") // 查找 code 字段值为 D42 的记录

	// Update - 将 product 的 price 更新为 200
	db.Model(&product).Update("Price", 200)
	// Update - 更新多个字段
	db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // 仅更新非零值字段
	db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})

	// Delete - 删除 product
	db.Delete(&product, 1)
}

GORM默认约定

  • 使用名为ID的字段作为主键
  • 使用结构体的蛇形复数作为表名
  • 字段名的蛇形作为列名
  • 使用CreateAt和UpdateAt作为创建和更新时间
  • 可以定义一个函数TableName()自定义model的表名,函数直接返回自定义的表名字符串

CRUD接口

详细内容可以参考GORM官方文档

创建

db.Create()参数是结构体指针

db.Select().Create()db.Omit().Create()分别可以指定列名创建和排除列名创建

db.Select("Name", "Age", "CreatedAt").Create(&user)
db.Omit("Name", "Age", "CreatedAt").Create(&user)

这两个调用分别等价于这两个SQL语句

INSERT INTO `users` (`name`,`age`,`created_at`) VALUES ("jinzhu", 18, "2020-07-04 11:05:21.775")
INSERT INTO `users` (`birthday`,`updated_at`) VALUES ("2020-01-01 00:00:00.000", "2020-07-04 11:05:21.775")

创建的时候可以指定标签,gorm:"column:columnName"可以指定列名,gorm:"default:defaultValue"可以指定默认值,gorm:"primary_key"可以指定主键

使用upsert处理冲突数据,clause.OnConflict可以处理冲突的数据,指定DoNothing为true表示数据冲突不做任何处理

image.png

查找

db.First()返回第一条数据,主键排序;会返回错误ErrRecordNotFound

db.Find()返回所有符合数据;找不到数据不会返回错误

db.Take()返回第一条数据,没有指定排序的属性

db.Last()获取最后一条数据,主键降序

image.png

上图的操作,数据保存在结构体user内,result中存储此次查询的相关属性.

指定条件查找:

  • 内联方式

image.png

  • Where方式

image.png

image.png

注意事项:

使用结构体作为查询条件的时候,只会查询非零字段,如果字段有零值需要使用map做条件或者使用Select()来选择字段

更新

db.Model().Update()

image.png

update更新单列的时候需要指定条件,不然会出现ErrMissingWhereClause

使用Model方法,会把该对象的主键的值用来构造条件

db.Save()可以保存所有字段

更新多列:

image.png

使用结构体或者map[]interface{}来更新多列

根据结构体来更新数据只会更新非零值,如果想要更新零值,需要使用Select()或者map[]interface{}的方式来更新多列

更新选定字段:

类似于创建的时候,使用Select和Omit来指定列

如果更新的时候需要计算,可以使用gorm.Expr()来做表达式的运算,例如db.Updates("age",gorm.expr("age * ? + ?", 2, 100))可以做到乘2加一百

删除

  • 如果model内含有deletedat字段,那么在这个model具有软删除的能力,删除掉的东西不会永久消失,只是目前查询不到;或者可以这样引入软删除功能

image.png

查询软删除的数据方式:使用Unscoped()

db.Unscoped().Where("age = 20").Find(&users)
// SELECT * FROM users WHERE age = 20;

也可以使用Unscoped()来永久删除数据

db.Unscoped().Delete(&order)
// DELETE from orders where id = 10;

GORM支持的数据库

SQLite PostgreSQL MySQL SQLServer这四种主流的数据库

事务

提供begin commit rollback三种操作

tx := db.Begin()可以开始一个事务,之后的操作要使用tx,结束之后使用tx.Commit()提交事务;

tx.Rollback()可以回滚事务

db.Transaction()可以自动提交,参数是一个函数,里面包含了事务的操作

HOOK

HOOK是删除,更新,增加,查找之前之后自动执行的函数;如果HOOK出现错误,后续的操作会被停止并且回滚事务

函数名是BeforeCreate()或者AfterCreate(),可以在创建之前执行和创建之后执行

GORM的性能优化

GORM对于写操作,会自动包装成事务执行,可以在gorm.Config{}中设置参数SkipDefaultTransaction : false关闭这个功能;

开启缓存预编译语句功能也可以提高性能,参数PrepareStmt : true

GORM的生态

常用的GORM工具如下:

image.png