GO的三个主流框架 | 青训营笔记

155 阅读7分钟

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

今天学习了GO主流开发框架GORM,Kites,Herts的使用方法,覆盖了ORM、RPC、HTTP三个领域

GORM

GORM是一款面向GO开发的,一种友好的ORM库

什么是ORM库

ORM(关系映射)库简单来说就是用于在关系型数据库和面向对象的编程语言堆之间的转换数据的编程技术。通过ORM技术,我们可以将关系数据库中某个数据表的结构关联到某个类/结构体上,并通过修改类/结构体来操作数据库,完成数据库的增删查改的任务

使用GORM

首先我们先需要安装GORM以及连接对应的数据库的驱动

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

这样子,我们就可以通过GORM连接Mysql数据库了,前提是需要安装好Mysql,在代码开始前,我们先需要导入GORM和Mysql数据驱动

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

GORM的增删查改

应用了文档中的代码

package main
​
import (
  "gorm.io/gorm"
  "gorm.io/driver/mysql"
)
​
type Product struct {
  gorm.Model
  Code  string
  Price uint
}
​
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{})
  if err != nil {
    panic("failed to connect database")
  }
​
  // 迁移 schema
  db.AutoMigrate(&Product{})
​
  // Create
  db.Create(&Product{Code: "D42", Price: 100})
​
  // Read
  var product Product
  db.First(&product, 1) // 根据整型主键查找
  db.First(&product, "code = ?", "D42") // 查找 code 字段值为 D42 的记录
​
  // Update - 将 product 的 price 更新为 200
  db.Model(&product).Update("Price", 200)
  // Update - 更新多个字段
  db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // 仅更新非零值字段
  db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})
​
  // Delete - 删除 product
  db.Delete(&product, 1)
}

查找

  // Read
  var product Product
  db.First(&product, 1) // 根据整型主键查找
  db.First(&product, "code = ?", "D42") // 查找 code 字段值为 D42 的记录

对应增删改查中的“查”。First 方法返回符合指定条件的首个记录值;值得注意的是,使用 First 方法进行查询时,如果查找不到数据会返回 ErrRecodeNotFound 错误。可以使用 Find 查询多条记录,而 Find 方法在查询不到数据的时候并不会返回错误。 还有很多关于GORM的使用方法,建议各位去看文档哦,我也不好直接复制文档的内容(笑哭)

GORM事务

数据库事务(transaction) 是访问并可能操作各种数据项]的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。举个例子,假设有一个电商网站数据库,涉及创建订单和配置库存两个操作,如果创建订单完成后配置库存失败了,那么理论上创建订单也应该被自动回滚以避免数据不一致,通过事务系统,我们可以将这两个操作划入一个事务,这样,当其中一个操作出现错误,其他操作便会被自动回滚。

使用事务
db.Transaction(func(tx *gorm.DB) error {
  // 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db')
  if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil {
    // 返回任何错误都会回滚事务
    return err
  }

  if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil {
    return err
  }

  // 返回 nil 提交事务
  return nil
})

手动开启和结束

// 开始事务
tx := db.Begin()
​
// 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db')
tx.Create(...)
​
// ...// 遇到错误时回滚事务
tx.Rollback()
​
// 否则,提交事务
tx.Commit()

GORM HOOK

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

Kitex

Kitex是字节跳动内部的 Golang 微服务 RPC 框架,具有高性能强可扩展的特点,在字节内部已广泛使用。如今越来越多的微服务选择使用 Golang,如果对微服务性能有要求,又希望定制扩展融入自己的治理体系,Kitex 会是一个不错的选择。

RPC

RPC(Remote procedure call,远程过程调用)是指计算机程序导致过程(子例程)在不同的地址空间(通常在共享网络上的另一台计算机上)中执行,其编码就像普通(本地)过程调用一样,程序员没有显式编码远程交互的详细信息。也就是说,程序员编写的代码基本相同,无论子例程是执行程序的本地还是远程的。简单来说,通过使用 RPC,我们可以像调用方法一样快捷的与远程服务进行交互。

使用Kitex(服务端)

Kitex 目前对 Windows 的支持并不完善,建议使用虚拟机或 WSL2 进行测试。

go install github.com/cloudwego/kitex/tool/cmd/kitex@latest
​
go install github.com/cloudwego/thriftgo@latest

接下来,定义 IDL,命名为 echo.thrift

namespace go api
​
struct Request {
    1: string message
}
​
struct Resposne {
    1: string message
}
​
service Echo {
    Reponse echo(1: Request req)
}

接口描述语言(Interface definition language,IDL) 是一种语言的通用术语,它允许用一种语言编写的程序或对象与用未知语言编写的另一个程序进行通信。 我们可以使用 IDL 来支持 RPC 的信息传输定义。Kitex 默认支持 thriftproto3 两种 IDL,而在底层传输上,Kitex 使用扩展的 thrift 作为底层的传输协议。

//使用以下指令为我们的回声服务生成代码
kitex -module exmaple -service example echo.thrift

`-module` 表示生成的该项目的 go module 名,`-service` 表明我们要生成一个服务端项目,后面紧跟的 `example` 为该服务的名字。最后一个参数则为该服务的 IDL 文件。

运行 sh build.sh 以进行编译,编译结果会被生成至 output 目录 最后,运行 sh output/bootstrap.sh 以启动服务。服务会在默认的 8888 端口上开始运行。要想修改运行端口,可打开 main.go,为 NewServer 函数指定配置参数:

 addr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:9999")
  svr := api.NewServer(new(EchoImpl), server.WithServiceAddr(addr))

使用Kitex(客户端)

上例中,我们使用 Kitex 创建了一个回声服务端,接下来,我们通过创建一个客户端来调用我们的回声服务。以下项目代码假设您已正确导入上文中生成的回声服务代码。新建项目并创建 main.go 文件,编写代码:

import "example/kitex_gen/api/echo"
import "github.com/cloudwego/kitex/client"
...
c, err := echo.NewClient("example", client.WithHostPorts("0.0.0.0:8888"))
if err != nil {
  log.Fatal(err)
}

在编写完一个简单的客户端后,我们终于可以发起调用了。

$ go run main.go

结果

2021/05/20 16:51:35 Response({Message:my request})

Hertz

安装命令行工具 hz(依然,在此之前,请务必检查已正确设置 GOPATH 环境变量,并将 $GOPATH/bin 添加到 PATH 环境变量中):

go install github.com/cloudwego/hertz/cmd/hz@latest

hz 也可被用于为指定 IDL 生成服务代码。

使用 hz new 生成代码,然后使用 go mod tidy 拉取依赖。

在 main.go 文件,编写以下代码:

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() {
    h := server.Default(server.WithHostPoerts("127.0.0.1:8080"))
​
    h.GET("/ping", func(c context.Context, ctx *app.RequestContext) {
            ctx.JSON(consts.StatusOK, utils.H{"message": "pong"})
    })
​
    h.Spin()
}

今天的整理只有这些了,提前祝大家新年快乐~

引用

作者:HikariLan贺兰星辰
链接:juejin.cn/post/719066…