Go框架三件套(Gorm/Kitex/Hertz)介绍|青训营笔记
这是我参与【第五届青训营】伴学笔记创作活动的第5天。
一、本节课重点内容
- Gorm的使用方法
- Kitex的RPC定义方法、代码生成
- Hertz的路由使用方法、代码生成
二、详细知识点介绍
1.三件套介绍
- Gorm
- 迭代10+年的ORM(对象关系映射)框架
- 字节内部广泛使用,有丰富的开源扩展
- Kitex
- 字节内部的Golang微服务RPC框架
- 高性能,强可扩展
- 支持多协议、拥有丰富的开源拓展
- Hertz
- 字节内部的HTTP框架
- 高易用/高性能/高扩展
2. 三件套的使用
2.1 Gorm的使用
-
定义结构体 gorm model
- 一个简单的gorm model,包含code名和price两个var
type Product struct Code string Price uint -
定义model的表名
- 一个表名的返回函数
func (p Product) TableName() string{ return "product" } -
连接数据库
- 使用gorm连接数据库,打开mysql数据库,检查错误
db, err := gorm.Open( mysql.open(dsn:"user:password@tcp(127.0.0.1:3306)/dbname?") & gorm.Config{} ) if err != nil { panic() } -
创建数据、查询数据、更新数据、删除数据
//创建一个新的gorm model产品结构体,初始化值 db.Create(&Product{Code:"D42", Price:100}) //查询数据,一定要传递指针 var product Product db.First(&Product, conds:1) //根据整形主key查找(ID为主key) db.First(&Product, conds:"code=?","D42")//查询code为D42的Product //更新数据 db.Model(&Product).Update(column:"Price", value:200) //单字段 db.Model(&Product).Updates(Product{Price:200, Code:"F42"}) //仅更新非零值字段 db.Model(&Product).Updates(map[string]interface{}("Price":200,"Code":"F42"}) //删除数据 db.delete($Product, conds:1) -
Gorm支持的数据库
- Gorm支持MySQL/SQLServer/PostgreSQL/SQLite
- 通过驱动连接数据库,需要连接其他类型数据库可以复用、自行开发驱动
- 使用DSN进行连接
-
Gorm创建数据
- 使用clause.OnConflict处理数据冲突
db.Clauses(clause.OnConflict{DoNothing:true}) .Create(&p)- 使用default标签为字段定义默认值
type User struct{ ID int64 Name string 'gorm:"default:galeone"' Age int64 'gorm:"default:18"' -
Gorm查询数据
- First的使用
- 使用First时需要注意查不到时会返回ErrRecordNotFound
- 使用Find查询多条数据查不到不会返回错误
- 使用结构体作为查询条件
- 使用结构作为条件查询,gorm只查询非0值字段,如果字段值为0、false或其他零值则该字段不会被用于作为查询条件
- 可以使用map构建查询条件
- First的使用
-
Gorm更新数据
- 使用struct更新时只会更新非0值
- 更新零值需要使用map更新或select字段
-
Gorm删除数据
- 物理删除:Delete
- 软删除:DeletedAt
- 拥有软删除能力的model调用delete时,记录不会被从数据库中真正删除,但gorm会将deleteAt置为当前时间,不能通过正常的查询方法找到该数据
- 可以通过unscoped查询到被软删的数据
-
Gorm事务
- Begin
- 固化链接
- 实行开启sql的语句
- 返回对象
- Commit/rollback
- 提供了Transaction方法用于自动提交事务
db.Transaction(func(tx *gorm.DB) error())
- Begin
-
Gorm Hook
- 提供了CURD的Hook能力
- 在创建、查询、更新、删除等操作之前、之后自动调用的函数
- 如果任何hook返回错误,Gorm将停止后续操作并回滚事务。
-
性能提高
- 写操作保证数据完整性,封装在事务内运行,降低性能
- 可以使用SkipDefaultTransaction关闭默认事务
- 使用Prepare Stmt缓存预编译语句可以提高调用速度
-
gorm生态 github.com/go-gorm
- Gorm代码生成工具 /gen
- 分片库方案 /sharding
- 手动索引 /hints
- 乐观锁 /optimisticlock
- 读写分离 /dbresolver
- OpenTelemetry扩展 /opentelemetry
2.2 Kitex的使用
-
定义IDL
- 使用RPC需要知道对方的接口是什么,需要传递什么参数
- 需要知道返回值的样子
- 通过IDL约定双方的协议,可以知道对方接口的格式
namespace go api struct Request{ 1:string message } struct Response{ 1:string message } service Echo { Response echo(1:Request req) } -
Kitex生成代码
kitex -module example -service example echo.thrift- build.sh 构建脚本
- kitex_gen: IDL内容相关的生成代码,基础的client/server代码
- main.go 程序入口
- handler.go 用户在该文件中实现IDL service定义的方法
-
服务默认监听8888端口
type EchoImpl struct{} func (s *EchoImpl) Echo(ctx context.Context, req *api.Request) (resp *api.Response, err error){ //Your Code Here return } -
Client发起请求
//创建client echo.NewClient("example", client.WithHostPorts("0.0.0.0:8888")) //发起请求 req := &api.Request(Message: "my request") resp, err := c.Echo(context.Background(), req, callopt.WithRPCTimeout(3*time.Second)) -
Kitex服务注册与发现
- 对接主流服务注册/发现中心,如ETCD、Nacos
etcd.NewEtcdRegistry() etcd.NewEtcdResolver()
2.3 Hertz基本使用
- 实现、服务监听8080端口,注册get方法的路由函数
func main(){ h:=server.Default(server.WithHostPorts(hp:"127.0.0.1:8080") h.GET(relativePath:"/ping", func(c context.Context, ctx *app.RequestContext){ ctx.JSON(consts.StatusOK, utils.H{"ping":"pong"}) }) h.spin() } - 支持的路由
//GET h.GET(relativePath:"/get", func(c context.Context, ctx *app.RequestContext){} //POST h.POST(relativePath:"/post", func(c context.Context, ctx *app.RequestContext){} //PUT h.PUT(relativePath:"/put", func(c context.Context, ctx *app.RequestContext){} //DELETE h.DELETE(relativePath:"/delete", func(c context.Context, ctx *app.RequestContext){} //PATCH h.PATCH(relativePath:"/patch", func(c context.Context, ctx *app.RequestContext){} //HEAD h.HEAD(relativePath:"/head", func(c context.Context, ctx *app.RequestContext){} //OPTIONS h.OPTIONS(relativePath:"/options", func(c context.Context, ctx *app.RequestContext){} - 提供了参数路由和通配路由
- 参数路由 /:version
- 通配路由 /*action
- 静态路由>命名路由>通配路由
- 提供了参数绑定(需要传递指针)
- bind
- validate
- bindandvalidate
- Hertz中间件(根据注册位置分类)
- 客户端中间件
- 服务端中间件
- 终止中间件调用链的执行 c.Abort(WithMsg/Stats)
- Hertz Client
- 提供了HTTP Client用于帮助用户发送HTTP请求
- Hertz代码生成工具
- 提供了代码生成工具Hz
- 通过定义IDL文件生成代码
- Hertz性能
- 网络库NetPoll:需要注意切换库
- Json编解码Sonic:默认使用Sonic
- 使用sync.Pool复用对象
三、实践练习例子
-
使用Hertz、Kitex、Gorm搭建的具备一定业务逻辑的后端API笔记项目
- demoapi:API服务器,HTTP,Gorm/Kitex/Hertz
- demouser:用户数据管理,protobuf,Gorm/Kitex
- demonote:笔记数据管理,Thrift,Gorm/kitex
-
代码例子:见学习资料github。
四、个人总结
本节课主要介绍了Go三件套:Gorm/Kitex/Hertz的基本用法和实现方式。Gorm是go对接数据库的主要方式,其应用有独特的语法需要进行学习。Kitex是RPC的对接实现方式,用户只需定义IDL则可以使用自动代码生成工具进行生成,对接API。Hertz则是HTTP路由的一个实现方式。 本节课学习的内容偏基础使用,需要在实际的项目实践中进行深入学习。