这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天
课程主要内容
这节课主要学习了Go语言的三个框架:PRC框架Kitex、ORM框架Gorm、HTTP框架Hertz。以及一个实战案例。
课程具体内容
首先了解了go语言的PRC框架Kitex、ORM框架Gorm以及HTTP框架Hertz,并且了解了它们的API。接着了解了一个项目,接下来需要亲自实战加深理解。
Gorm
首先是Gorm,这是一个ORM框架。首先学习了如何通过Gorm实现CRUD操作。
1.连接数据库
首先需要通过Gorm连接数据库,目前Gorm支持MySql、SQLServer、SQLite等多个数据库。官方网站给出的连接数据库的demo如下:
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{}) }
user和password要换成要连接的数据库的账号密码,tcp()括号内写ip地址,3306是使用的端口号,dbname是要连接的schema的名字(大概)。后面是编码格式等。
Gorm通过驱动连接数据库,因此连接不同类型的数据库需要用不同的驱动,在使用时要导入不同的包。如连接mysql时,导入的是“driver/mysql”,而连接PostgreSQL需要导入“/driver/postgres”。驱动也可以根据需要自己编写驱动。
2.CREATE
主要还是依靠“db.Create(&XXX)”这个命令。如官方给的demo中该部分的代码为
db.Create(&Product{Code: "D42", Price: 100})
或者是先定义结构体,再创建。若要创建多个对象。就需要使用list结构体。 该语句的返回对象是一个Gorm对象。 对于数据冲突,Gorm提供了Upsert支持。主要是使用clause.OnConflict语句。
// Do nothing on conflict
DB.Clauses(clause.OnConflict{DoNothing: true}).Create(&user)
“DoNothing: true”是指如果发生了冲突,什么都不做。
.Create()后面继续加语句是不会起作用的,因为这里开始sql就开始执行了。
此外,Gorm使用default标签定义默认值。如
type User struct {
gorm.Model
Name string
Age *int `gorm:"default:18"`
Active sql.NullBool `gorm:"default:true"`
}
Age的默认值是18.
3.QUERY
查询:Gorm中提供了First()进行查询。但是如果找不到数据,First()会返回error。因此说在实际开发中会使用Where()后面跟.Find()这类的写法进行查询,如果查不到,会返回空数组。
// Struct
db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
// LIKE
db.Where("name LIKE ?", "%jin%").Find(&users)
注意:如果使用结构体进行查询时,只会查询非零值字段,因此要格外注意‘0’,false或者其他零值。
4.UPDATE
可以使用.Update()。 在使用.Update()更新单列时,必须要使用.Model()指定表明。
// Update with conditions
db.Model(&User{}).Where("active = ?", true).Update("name", "hello")
当使用Struct进行更新时,通常要使用map或者Select选择字段,因为Struct只会更新非零值。
5.DELETE
分为软删除和物理删除。 物理删除:直接使用db.delete()函数,数据如果删除就是真的删除了。
db.Delete(&email)
// DELETE from emails where id = 10;
// Delete with additional conditions
db.Where("name = ?", "jinzhu").Delete(&email)
软删除:在实际使用中用的较多。Gorm中使用gorm.DeletedAt字段,这样就能够软删了。使用Unscoped可以查询到软删的数据。
事务
主要提供了Begin,Commit,Rollback进行事务管理。
Kitex
Kitex是一个RPC框架。首先要定义IDL,约束双方的协议等,统一使用IDL管理接口,在使用时只看IDL部分不需要看源码定义的格式。
$ kitex -module example -service example echo.thrift
-module 表示生成的该项目的 go module 名,-service 表明我们要生成一个服务端项目,后面紧跟的 example 为该服务的名字。最后一个参数则为该服务的 IDL 文件
package main
import (
"context"
"example/kitex_gen/api"
)
// EchoImpl implements the last service interface defined in the IDL.
type EchoImpl struct{}
// Echo implements the EchoImpl interface.
func (s *EchoImpl) Echo(ctx context.Context, req *api.Request) (resp *api.Response, err error) {
// TODO: Your code here...
return
}
在框架生成的代码里直接写即可。逻辑不一定都写在这里,如果逻辑复杂,仍然要分层。
c, err := echo.NewClient("example", client.WithHostPorts("0.0.0.0:8888"))
创建client的代码。
然后发起调用即可。但是接下来可以进行优化,初始化操作等可以进行优化。
Kitex的服务注册已经对接了主流的注册中心(Nacos等)。
且目前Kitex的扩展也很丰富,就是对windows的支持不是太好。
本节课对Kitex主要是进行了介绍,实战的话还是需要进一步查看手册。目前Kitex对windows支持不够好。
Hertz
Hertz是一个http框架。
func main() {
h := server.Default()
h.GET("/ping", func(c context.Context, ctx *app.RequestContext) {
ctx.JSON(consts.StatusOK, utils.H{"message": "pong"})
})
h.Spin()
}
Hertz中有两个方法:server.Default()和server.New(),这两个方法的区别是server.Default()会直接集成一个中间件。
上面代码中的h.Spin()指开启自选。
Hertz是两个上下文,这个来自于工程经验,一个用于专注于传递原信息,一个专注于请求的处理。
Hertz提供了GET,POST,PUT,DELETE,ANY等方法用于注册路由(看来支持的都差不多)
支持路由组的功能,其使用是:
v1 = h.Group("/v1")
{
XXXXXXXX
}
Hertz支持参数路由和通配路由。Hertz 支持使用 :name 这样的命名参数设置路由,并且命名参数只匹配单个路径段。使用*path这样的通配参数设置路由,并且通配参数会匹配所有内容。(通配路由匹配的会更多)实例区别:分别配置/user/:name和/src/*path,在使用参数路由时,“/user/you”是匹配的,“/user/gordon/profile”和“/user”不匹配。而如果使用通配路由,“/src/”、“/src/somefile.go”这些形式都认为是匹配的。
具体使用代码:
//参数路由
func main(){
h := server.Default(server.WithHostPorts("127.0.0.1:8080"))
// This handler will match: "/hertz/version", but will not match : "/hertz/" or "/hertz"
h.GET("/hertz/:version", func(ctx context.Context, c *app.RequestContext) {
version := c.Param("version")
c.String(consts.StatusOK, "Hello %s", version)
})
h.Spin()
}
//通配路由
func main(){
h := server.Default(server.WithHostPorts("127.0.0.1:8080"))
// However, this one will match "/hertz/v1/" and "/hertz/v2/send"
h.GET("/hertz/:version/*action", func(ctx context.Context, c *app.RequestContext) {
version := c.Param("version")
action := c.Param("action")
message := version + " is " + action
c.String(consts.StatusOK, message)
})
h.Spin()
}
Hertz中的路由优先级为:静态路由>命名路由>通配路由。当都命中时,按优先级访问。
Hertz参数绑定:把HTTP中请求的参数转到结构体中。支持bind,validate和bindAndvalidate函数。是go-tag的形式。
Hertz的中间件:分为客户端中间件和服务端中间件。通常对一些通用的逻辑,会考虑使用中间件。 此外Hertz还提供了代码生成工具Hz,通过定义IDL后生成客户端和服务端代码。
实战
主要是将之前学的这三个框架组合起来。主要技术栈包括Go,Mysql,Gorm,Kitex,Hertz,Ectd。并且跟着老师熟悉了一下主要的代码。
总结
本节课主要简单地了解了Gorm、Hertz和Kitex这三个框架的功能以及基本使用。把课上的内容跟三个框架的文档对比了后就发现,课上重点讲了常用的功能,对很多边边角角的知识讲的不多。这部分还需要查看官方文档进行了解。对于相关的项目,必须经过实际的操作才能够加深理解。