这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天
前言
本文主要介绍Go语言的三个主流开发框架之一的Gorm。
它是一个迭代了10年以上的功能强大的orm框架,有着非常丰富的开源拓展。
ORM介绍
在学习Gorm前,你应该先了解什么是 ORM。
过去在Java的学习中,我们常见的ORM框架有Mybatis, MyBatis-Plus, Hibernate。
ORM的全称叫做对象关系映射,英文全称:Object–relational mapping。
使用orm的原因:
- ORM是一种用于在关系数据库和面向对象的编程语言堆之间转换数据的编程技术
- 通过ORM技术,我们可以将关系数据库中某个数据表的结构关联到某个类/结构体上,并通过修改类/结构体实例的方式轻易的完成数据库增删改查(CRUD)的任务
- 通过ORM技术,我们得以以一种更加友好且高效的方式,在尽量不接触 SQL 语句的情况下操作数据库
GORM的使用
- GORM 并不包含在 Go 标准库中,因此,我们需要先安装 GORM 及需要连接对应数据库的驱动。
- Gorm 官方支持的数据库类型有:MySQL, PostgreSQL, SQlite, SQL Server。可以通过以下命令通过 Go Module 拉取并添加 Gorm 及 MySQL 数据库驱动:
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql
可以通过import导入gorm和mysql的数据驱动
Gorm 设计规范
默认情况下,GORM 使用 ID 作为主键,使用结构体名的蛇形复数作为表名,字段名的蛇形作为列名,并使用 CreatedAt、UpdatedAt 字段追踪创建、更新时间。
Gorm 创建数据
-
使用Upsert
通过 clause.OnConflict 处理数据冲突
-
通过使用 default 标签为字段定义默认值
如,
gorm:"default:18"
Gorm 查询数据
-
First踩坑注意:
- 使用First时,需要注意查询不到数据会返回ErrRecordNotFound。
- 使用Find查询多条数据,查询不到数据不会返回错误。
-
使用结构体作为条件查询时
- GORM只会查询非零值字段。这意味着如果你的值为0,",false或其他零值,该字段不会被用于用于构建查询条件,使用Map来构建查询条件。
Gorm 更新数据
使用Struct更新时,只会更新非零值,如果需要更新零值可以使用Map更新或使用Select 选择字段。
//条件更新单个列
db.Model(&User(ID: 111).Where( query: "age > ?",args...: 18).Update( column: "name", value: "hello")
//更新多个列
// 根据 struct更新属性,只会更新非零值的字段
db.Model(&User{ID: 111}).Updates(User{Name: "helo",Age: 18})
// 根据“map’更新属性
db.Model(&User(ID: 111)).Updates(map[stringlintenface}{"name": "hello", "age": 18, "actived": false))
//更新选定字段
db.Model(&User{ID: 111)).Select( query: "name").Updates(map[stringlinterface}{"name": "hello","age": 18,"actived": false})
// SQL 表达式更新
db.Model(&User(ID: 111}).Update( column: "age", gorm.Expr( expr: "age * ? + ?", args... .2, 100)
Gorm 物理删除和软删除
- 物理删除:数据库层面删除数据
db.Delete(&User.conds...: 10) // DELETE FROM users WHERE id = 10;
db.Delete(&User,conds...: "10") // DELETE FROM users WHERE id = 10;
db.Delete(&User ,[lint(1,2,3)) // DELETE FROM users WHERE id IN (1,2,3);
db.Where( query:"name LIKE ?"args... "%jinzhu%").Delete(User1}) // DELETE from users where name LIKE "%jinzhu%";
db.Delete(User1, conds.. "email LIKE ?", "%jinzhu%") // DELETE from users where name LIKE "%jinzhu%";
- 软删除:记录不会被从数据库中真正删除,但会记录删除时间
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
type User struct {
ID int64
Namestring `gorm:"default:galeone"`
Ageint64 `gorm:"default:18"`
Deleted gorm.DeletedAt
}
func main(
db,err := gorm,0pen(mysgl.Open( dsn:"username:passwordatcp(localhost:9910)/database?charset=utf8"),&gorm.Config{})
if err != nil {
panic( v:"failed to connect database")
}
// 删除一条
u:= User{ID:111} // user 的 ID 是111
db.Delete(&u)
//在查询时会忽略被软删除的记录
db.Where( query: "age = 20").Find(&users) // SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;
//在查询时不会忽略被软删除的记录
db.Unscoped().Where(query: "age = 20").Find(&users) // SELECT * FROM uSers WHERE age = 20;
特性:
- GORM 提供了 gorm.DeletedAt 用于帮助用户实现软删除。
- 拥有软删除能力的 Model 调用 Delete 时,记录不会被从数据库中真正删除。但 GORM 会将 DeletedAt 置为当前时间,并且你不能再通过正常的查询方法找到该记录。
- 使用 Unscoped 可以查询到被软删的数据
- 详情:gorm.cn/zh_CN/docs/…
GORM 事务
- Gorm 提供了 Begin、Commit、 Rollback 方法用于使用事务。
- Gorm 提供了 Tansaction 方法用于自动提交事务,避免用户漏写Commit、 Rollback。
其实蛮有用,解决了忘记加事务提交以及使用重复事务相关代码的问题。
Hook
Hook是指在创建、查询、更新、删除等操作之前、之后调用的函数。
Hook使用:
- GORM提供了CURD的Hook能力
- 如果您已经为模型定义了指定的方法,它会在创建、更新、查询、删除之前、之后自动被调用。
- 如果任何Hook错误,GORM 将停止后续的操作并回滚事务。
- gorm.cn/zh_CN/docs/…
GORM性能提高
修改默认配置&gorm.Config{}大括号中的配置。
- 对于写操作,为确保数据的完整性,Gorm会将它们封装在事务内运行,但会降低性能,可使用SkipDefaultTransaction 关闭默认事务。
- 预编译可提高性能,使用PrepareStmt 缓存预编译语句可以提高后续调用的速度。
- 其他请看:gorm.cn/zh_CN/docs/…
扩展生态
常用:
- GORM 代码生成工具
- GORM 分片库方案
- GORM 手动索引
- GORM 乐观锁
- GORM 读写分离
- GORM OpenTelemetry 扩展 详细内容见引用。
心得
学习了主流框架之一——gorm,明天继续学习kitex,都要花时间消化,不过获益匪浅
引用
ppt:Go 框架三件套详解.pptx - 飞书云文档 (feishu.cn) Gorm文档:gorm.cn
扩展详细内容: 代码生成工具:github.com/go-gorm/gen 分片库方案:github.com/go-gorm/sha… 手动索引:github.com/go-gorm/hin… 乐观锁:github.com/go-gorm/opt… 读写分离:github.com/go-gorm/dbr… OpenTelemetry 扩展:github.com/go-gorm/ope…