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

66 阅读4分钟

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

1 Gorm

Gorm是一款ORM框架,ORM是“对象-关系-映射”的简称,Go语言中常用的ORM框架有很多,如gorm、facebook-ent、xorm、upper/db、gorose等,这里以gorm为例。

1.1 Gorm介绍

Gorm 是 Golang 的一个 orm 框架。ORM 是通过实例对象的语法,完成关系型 数据库的操作,是"对象-关系映射"(Object/Relational Mapping) 的缩写。使用 ORM 框架可以让我们更方便的操作数据库。

Gorm官方支持的数据库类型有: MySQL, PostgreSQL, SQlite, SQL Server

1.2 功能

  • Create,Save,Update,Delete,Find 中钩子方法

  • 支持 Preload、Joins 的预加载

  • 事务,嵌套事务

  • Context、预编译模式、DryRun 模式

  • 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD

1.3 数据库连接

package main
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"
    // loc 设置本地系统的时间, 前提 parseTime=True
    // 更多参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 
	_, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	//db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{Logger:logger.Default.LogMode(logger.Info)})  打印sql日志
	if err != nil {
		panic(err) // 如果数据库不存在会报错

	}
}

1.4 CRUD

package main

import (
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"log"
	"os"
	"time"
)

type Product struct {
	gorm.Model
	Code  string
	Price uint
}
func main() {
	// 日志配置
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
		logger.Config{
			SlowThreshold:             time.Second, // 慢 SQL 阈值
			LogLevel:                  logger.Info, // 日志级别为info
			IgnoreRecordNotFoundError: true,        // 忽略ErrRecordNotFound(记录未找到)错误
			Colorful:                  true,        // 彩色打印
		},
	)

	dsn := "root:123@tcp(127.0.0.1:3306)/gorm_test?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: newLogger,
	})
	if err != nil {
		panic(err) // 如果数据库不存在会报错
	}
	//1 迁移 表,可以写多个
	//db.AutoMigrate(&Product{})

	//2 插入数据
	db.Create(&Product{Code: "D42", Price: 100})
	db.Create(&Product{Code: "D43", Price: 150})

	//3 查询数据
	var product Product  // 定义空Product结构体对象
	db.First(&product, 1) // 根据整型主键查找
	db.First(&product, "code = ?", "F43") // 查找 code 字段值为 D43 的记录
	//fmt.Println(product)

	//4  更新 - 将 product 的 price 更新为 200
	db.Model(&product).Update("Price", 200)
	// Update - 更新多个字段
	db.Model(&product).Updates(Product{Price: 200, Code: "F43"}) // 仅更新非零值字段
	db.Model(&product).Updates(map[string]interface{}{"Price": 300, "Code": "F42"})

	//5  Delete - 删除 product
	db.Delete(&product, 1)  // 软删除
}

1.5 事务

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

2 Kitex

Kitex 是一款强可扩展性的 Go RPC 框架。

架构图如下:

image.png

2.1 安装

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

2.2 server

创建IDL文件

Kitex 典型的使用场景就是基于 thrift 定义的 IDL 来定义服务接口,实现客户端和服务端的通信。

这里我们新建一个demo的服务定义: kstudy.thrift

namespace go api
 
struct Request {
    1: string message1
    2: string message2
}
 
struct Response {
    1: string message
}
 
service KStudy {
    Response Concat(1: Request req)
}

可以看到,我们定义了一个KStudy服务,包含一个Concat接口,语义是将 Request 中的 message1 和 message2 两个字符串拼接起来,通过 Response 返回。

基于thrift生成代码,所以只需要在项目目录运行

kitex -service kstudy kstudy.thrift

2.3 client

我们在 kstudy 下新建client文件夹,用于实现客户端相关逻辑。新增 main.go 作为客户端的启动入口。由于我们目前只是单机的 server 和 client 交互,没有复杂的服务发现逻辑,需要通过添加client.Option来指定调用的 host 和 port。

package main
 
import (
	"context"
	"log"
 
	"github.com/ag9920/kstudy/kitex_gen/api"
	"github.com/ag9920/kstudy/kitex_gen/api/kstudy"
	"github.com/cloudwego/kitex/client"
)
 
func main() {
	client, err := kstudy.NewClient("kstudy", client.WithHostPorts("0.0.0.0:8888"))
	if err != nil {
		log.Fatal(err)
	}
	req := &api.Request{
		Message1: "message1",
		Message2: "message2",
	}
	resp, err := client.Concat(context.Background(), req)
	if err != nil {
		log.Fatal(err)
	}
	log.Println(resp)
}
 

3 Hertz

Hertz[həːts] 是一个 Golang 微服务 HTTP 框架,在设计之初参考了其他开源框架 fasthttp、gin、echo 的优势, 并结合字节跳动内部的需求,使其具有高易用性、高性能、高扩展性等特点,目前在字节跳动内部已广泛使用。 如今越来越多的微服务选择使用 Golang,如果对微服务性能有要求,又希望框架能够充分满足内部的可定制化需求,Hertz 会是一个不错的选择。

3.1 安装Hertz

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

3.2 使用

执行hz new初始化项目,项目初始化后,hertz会自动创建对应项目文件,文件结构如下

.
├── biz
│   ├── handler
│   │   └── ping.go
│   └── router
│       └── register.go
├── go.mod
├── main.go
├── router.go
└── router_gen.go

3.3 获取请求参数

通过c.Query获取路径参数

func Person(ctx context.Context, c *app.RequestContext) {
	name := c.Query("name")
	c.JSON(200, utils.H{
		"data": name,
	})
}

通过c.Param获取路径参数

func HelloPerson(ctx context.Context, c *app.RequestContext) {
   name := c.Query("name")
   age := c.Param("age")
   c.JSON(200, utils.H{
      "age":  age,
      "name": name,
   })
}

3.4 路由注册

r.GET("/person/:age", hello.HelloPerson)