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

75 阅读4分钟

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

一、本堂课主要内容

  • Go框架三件套

    • Gorm
    • Kitex
    • Hertz

二、知识点详解

三件套简介

  • Gorm

    Gorm是功能强大的ORM框架,在字节内部有广泛的使用和丰富的开源拓展

  • Kitex

    Kitex是字节内部Golang微服务RPC框架,具有高性能、强可拓展性的特点,支持多协议并且具有丰富的开源拓展

  • Hertz

    字节内部的HTTP框架,参考了其他开源框架的优势,结合字节内部自身需求,具有高易用性、高性能和高可拓展的特点

三件套的基本使用

Gorm的基本使用

package main

import (
   "fmt"
   "gorm.io/driver/mysql"
   "gorm.io/gorm"
)

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

func (p Product) TableName() string {
   return "product"
}

func main() {
   dsn := "root:root@tcp(101.43.254.215:3306)/zzy_demo?charset=utf8mb4&parseTime=True&loc=Local"
   db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
   if err != nil {
      panic("failed to connect database")
   }

   // Migrate the schema
   db.AutoMigrate(&Product{})

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

   // Read
   var product Product
   db.First(&product, 1)                 // find product with integer primary key
   db.First(&product, "code = ?", "D42") // find product with code D42
   fmt.Println(product)

   // Update - update product's price to 200
   db.Model(&product).Update("Price", 200)
   fmt.Println(product)
   // Update - update multiple fields
   db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // non-zero fields
   db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})

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

使用navicat查看表和数据是否写入数据库:

image.png

Gorm约定:使用ID的字段作为主键;使用CreatedAt、UpdatedAt字段作为创建、更新时间;使用结构体的蛇形负数作为表名;使用字段名的蛇形作为表名

Gorm连接到数据库:

这里以mysql为例,Gorm支持MySQL,PostreSQL,SQLite和SQL Server,几乎囊括了所有主流数据库,[详细信息参考](连接到数据库 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.)

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{})
}

定义默认值:

type Product struct {
   gorm.Model
   ID    uint   `gorm:"primarykey"`
   Code  string `gorm:"default:golang"`
   Price uint   `gorm:"default:100"`
}

查询: [参考](Go语言标准库文档中文版 | Go语言中文网 | Golang中文社区 | Golang中国 (studygolang.com))

更新: [参考](更新 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.)

删除: 参考

事务:

image.png

image.png

参考

Hook:

Hook 是在创建、查询、更新、删除等操作之前、之后调用的函数。

如果您已经为模型定义了指定的方法,它会在创建、更新、查询、删除时自动被调用。如果任何回调返回错误,GORM 将停止后续的操作并回滚事务。

Hook方法的函数签名应该是 func(*gorm.DB) error

// 开始事务
BeforeSave BeforeCreate
// 关联前的 save
// 插入记录至 db 
// 关联后的
save AfterCreate
// 提交或回滚事务 
AfterSave

代码实例:

func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
  u.UUID = uuid.New()

  if !u.IsValid() {
    err = errors.New("can't save invalid data")
  }
  return
}

func (u *User) AfterCreate(tx *gorm.DB) (err error) {
  if u.ID == 1 {
    tx.Model(u).Update("role", "admin")
  }
  return
}

[参考](Hook | GORM - The fantastic ORM library for Golang, aims to be developer friendly.)

Gorm 性能提高:

image.png

Kitex的基本使用

由于暂时没有针对 Windows 做支持,如果本地开发环境是 Windows 建议使用 WSL2

假如你的虚拟机还没有配置GO开发环境,参考以下信息:

准备 Golang 开发环境

  1. 如果您之前未搭建 Golang 开发环境, 可以参考 Golang 安装
  2. 推荐使用最新版本的 Golang,我们保证最新三个正式版本的兼容性(现在 >= v1.16)。
  3. 确保打开 go mod 支持 (Golang >= 1.15时,默认开启)
  4. kitex 暂时没有针对 Windows 做支持,如果本地开发环境是 Windows 建议使用 WSL2

安装代码生成工具

首先,我们需要安装使用本示例所需要的命令行代码生成工具:

  1. 确保 GOPATH 环境变量已经被正确地定义(例如 export GOPATH=~/go)并且将$GOPATH/bin添加到 PATH 环境变量之中(例如 export PATH=$GOPATH/bin:$PATH);请勿将 GOPATH 设置为当前用户没有读写权限的目录
  2. 安装 kitex:go install github.com/cloudwego/kitex/tool/cmd/kitex@latest
  3. 安装 thriftgo:go install github.com/cloudwego/thriftgo@latest

安装成功后,执行 kitex --version 和 thriftgo --version 应该能够看到具体版本号的输出(版本号有差异,以 x.x.x 示例):

$ kitex --version
vx.x.x

$ thriftgo --version
thriftgo x.x.x

基本使用

image.png

创建Client和发起请求

image.png

Kitex服务注册与发现

image.png

image.png

Hertz的基本使用

package main

import (
   "context"

   "github.com/cloudwego/hertz/pkg/app"
   "github.com/cloudwego/hertz/pkg/app/server"
   "github.com/cloudwego/hertz/pkg/common/utils"
   "github.com/cloudwego/hertz/pkg/protocol/consts"
)

func main() {
   // Default creates a hertz instance with default middlewares.
   h := server.Default()

   // GET is a shortcut for router.Handle("GET", path, handle).
   h.GET("/ping", func(c context.Context, ctx *app.RequestContext) {
      ctx.JSON(consts.StatusOK, utils.H{"message": "pong"})
   })

   // Spin runs the server until catching os.Signal or error returned by h.Run().
   h.Spin()
}

路由

Hertz 提供了 GETPOSTPUTDELETEANY 等方法用于注册路由,分别用于注册对应的HTTP Method

示例程序:

package main

import (
	"context"
	"github.com/cloudwego/hertz/pkg/app"
	"github.com/cloudwego/hertz/pkg/app/server"
	"github.com/cloudwego/hertz/pkg/protocol/consts"
)

func main(){
	h := server.Default(server.WithHostPorts("127.0.0.1:8080"))

	h.StaticFS("/", &app.FS{Root: "./", GenerateIndexPages: true})

	h.GET("/get", func(ctx context.Context, c *app.RequestContext) {
		c.String(consts.StatusOK, "get")
	})
	h.POST("/post", func(ctx context.Context, c *app.RequestContext) {
		c.String(consts.StatusOK, "post")
	})
	h.PUT("/put", func(ctx context.Context, c *app.RequestContext) {
		c.String(consts.StatusOK, "put")
	})
	h.DELETE("/delete", func(ctx context.Context, c *app.RequestContext) {
		c.String(consts.StatusOK, "delete")
	})
	h.PATCH("/patch", func(ctx context.Context, c *app.RequestContext) {
		c.String(consts.StatusOK, "patch")
	})
	h.HEAD("/head", func(ctx context.Context, c *app.RequestContext) {
		c.String(consts.StatusOK, "head")
	})
	h.OPTIONS("/options", func(ctx context.Context, c *app.RequestContext) {
		c.String(consts.StatusOK, "options")
	})
	h.Any("/ping_any", func(ctx context.Context, c *app.RequestContext) {
		c.String(consts.StatusOK, "any")
	})
	h.Handle("LOAD","/load", func(ctx context.Context, c *app.RequestContext) {
		c.String(consts.StatusOK, "load")
	})
	h.Spin()
}

此外Hertz还支持路由组、参数路由和通配路由等等功能,[具体参考](路由 | CloudWeGo)

[其他内容也一并参考文档](基本特性 | CloudWeGo)