Go 框架三件套 | 青训营笔记

117 阅读6分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 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这三个框架的功能以及基本使用。把课上的内容跟三个框架的文档对比了后就发现,课上重点讲了常用的功能,对很多边边角角的知识讲的不多。这部分还需要查看官方文档进行了解。对于相关的项目,必须经过实际的操作才能够加深理解。