Go 框架三件套详解| 青训营笔记
这是我参与「第五届青训营 」笔记创作活动的第5天
今天主要对Go 框架三件套详解(Web/RPC/ORM)进行学习。
一、本堂课重点内容:
本次课程讲了以下几个方面:
1.ORM框架-Gorm
2.RPC 框架 Kitex
3.HTTP 框架 Hertz
二、详细知识点介绍:
1.ORM框架Gorm
Gorm是使用Go语言编写的ORM框架,它有着对开发者友好、支持主流数据库、文档齐全等优势。以下是使用Gorm连接MySQL数据库的Go语言程序代码:
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
dsn := "root:root@tcp(localhost:3306)/dbtest?charset=utf8mb4&parseTime=True&loc=Local"
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
//延时关闭数据库连接
defer db.Close()
}
在Gorm框架中,我们需要定义模型,就拿用户表(id,name,age)举例:
//我们需要定义一个结构体User作为模型
type User struct{
ID int `gorm:"column: id"`
Name string `gorm:"column: name"`
Age int `gorm:"column: age"`
}
以下是对MySQL数据库CURD简单操作代码:
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
//我们需要定义一个结构体User作为模型
type User struct{
ID int `gorm:"column: id"`
Name string `gorm:"column: name"`
Age int `gorm:"column: age"`
}
func main() {
dsn := "root:root@tcp(localhost:3306)/dbtest?charset=utf8mb4&parseTime=True&loc=Local"
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
//延时关闭数据库连接
defer db.Close()
//1.增加数据
u1 := &User{ID:1001,Name:"Jack",Age:18}
result := db.Create(u1) // 通过数据的指针来创建
/*其中result中包含
result.Error // 返回 error
result.RowsAffected // 返回插入记录的条数
*/
//2.查询数据
u2:=User{}
db.First(&u2)//查询数据库中的第一条数据放入u2中
var user User
var users []User
// 获取全部记录
result := db.Find(&users)/查询数据库中的第一条数据放入users中
//3.更新数据
db.Model(&User{ID:1001}).Update("Lucy", 20)
//4.删除数据
db.Delete(&User{ID:1001})
}
此外,Gorm还提供事物、Hook等高级功能。
2.RPC框架Kitex
Kitex是一个高性能、强可扩展性的 Go RPC 框架,它的使用场景就是基于 thrift 定义的 IDL 来定义服务接口,实现客户端和服务端的通信。下面是一个IDL:
namespace go api
struct Request {
1: string message
}
struct Response {
1: string message
}
service KStudy {
Response ehco(1: Request req)
}
如果我们要进行RPC,就需要知道对方的接口是什么,需要传什么参数,同时也需要知道返回值是什么样的。这时候,就需要通过IDL来约定双方的协议,就像在写代码的时候需要调用某个函数,我们需要知道函数签名一样。
由于目前Kitex不支持Windows操作系统,所以我对其知识点的学习更多停留在理论知识上,无法对其进行实践操作,在使用Go语言进行项目的微服务架构时,Kitex是一个不二之选。
Kitex的架构设计图如下:
具体文档参考:Kitex官网
3.HTTP框架Hertz
Hertz是一个 Golang 微服务 HTTP 框架,使其具有高易用性、高性能、高扩展性等特点,目前在字节跳动内部已广泛使用。下面是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() {
h := server.Default()
h.GET("/ping", func(c context.Context, ctx *app.RequestContext) {
ctx.JSON(consts.StatusOK, utils.H{"message": "pong"})
})
h.Spin()
}
此外,我们还可以使用Hert 自带的命令行工具hz配合IDL帮助我们快速生成基础代码。
具体文档:Hertz官网
三、实践练习例子:
项目功能模块如下图:
项目调用关系如下图:
Hertz关键代码如下:
// CreateNote create note info
func CreateNote(ctx context.Context, c *app.RequestContext) {
var noteVar NoteParam
if err := c.Bind(¬eVar); err != nil {
SendResponse(c, errno.ConvertErr(err), nil)
return
}
if len(noteVar.Title) == 0 || len(noteVar.Content) == 0 {
SendResponse(c, errno.ParamErr, nil)
return
}
claims := jwt.ExtractClaims(ctx, c)
userID := int64(claims[constants.IdentityKey].(float64))
err := rpc.CreateNote(context.Background(), ¬edemo.CreateNoteRequest{
UserId: userID,
Content: noteVar.Content, Title: noteVar.Title,
})
if err != nil {
SendResponse(c, errno.ConvertErr(err), nil)
return
}
SendResponse(c, errno.Success, nil)
}
Kitex的Client关键代码如下:
func initNoteRpc() {
r, err := etcd.NewEtcdResolver([]string{constants.EtcdAddress})
if err != nil {
panic(err)
}
c, err := noteservice.NewClient(
constants.NoteServiceName,
client.WithMiddleware(middleware.CommonMiddleware),
client.WithInstanceMW(middleware.ClientMiddleware),
client.WithMuxConnection(1), // mux
client.WithRPCTimeout(3*time.Second), // rpc timeout
client.WithConnectTimeout(50*time.Millisecond), // conn timeout
client.WithFailureRetry(retry.NewFailurePolicy()), // retry
client.WithSuite(trace.NewDefaultClientSuite()), // tracer
client.WithResolver(r), // resolver
)
if err != nil {
panic(err)
}
noteClient = c
}
// CreateNote create note info
func CreateNote(ctx context.Context, req *notedemo.CreateNoteRequest) error {
resp, err := noteClient.CreateNote(ctx, req)
if err != nil {
return err
}
if resp.BaseResp.StatusCode != 0 {
return errno.NewErrNo(resp.BaseResp.StatusCode, resp.BaseResp.StatusMessage)
}
return nil
}
Kitex的Server关键代码如下:
type CreateNoteService struct {
ctx context.Context
}
// NewCreateNoteService new CreateNoteService
func NewCreateNoteService(ctx context.Context) *CreateNoteService {
return &CreateNoteService{ctx: ctx}
}
// CreateNote create note info
func (s *CreateNoteService) CreateNote(req *notedemo.CreateNoteRequest) error {
noteModel := &db.Note{
UserID: req.UserId,
Title: req.Title,
Content: req.Content,
}
return db.CreateNote(s.ctx, []*db.Note{noteModel})
}
Gorm使用代码如下:
type User struct {
gorm.Model
UserName string `json:"user_name"`
Password string `json:"password"`
}
func (u *User) TableName() string {
return constants.UserTableName
}
// MGetUsers multiple get list of user info
func MGetUsers(ctx context.Context, userIDs []int64) ([]*User, error) {
res := make([]*User, 0)
if len(userIDs) == 0 {
return res, nil
}
if err := DB.WithContext(ctx).Where("id in ?", userIDs).Find(&res).Error; err != nil {
return nil, err
}
return res, nil
}
// CreateUser create user info
func CreateUser(ctx context.Context, users []*User) error {
return DB.WithContext(ctx).Create(users).Error
}
// QueryUser query list of user info
func QueryUser(ctx context.Context, userName string) ([]*User, error) {
res := make([]*User, 0)
if err := DB.WithContext(ctx).Where("user_name = ?", userName).Find(&res).Error; err != nil {
return nil, err
}
return res, nil
}
四、课后个人总结:
通过对Go框架三件套进行学习,让我在Go语言的学习上更上一层楼,开始接触了各种框架,了解了Gorm/Kitex/Hertz是什么,并且熟悉了三件套的基本语法,最后通过一个项目实战,将三者结合在一起进行学习,使得我在使用Go语言进行项目开发时更加标准化。