Day2-Go框架三件套初探 | 青训营笔记

91 阅读5分钟

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

前言

下面笔记简单记录我作为一个初学者使用框架的过程。

Hertz 初体验

首先在 官网 上下载安装 Hertz,因为后面的 Kitex 只能运行在 Linux 系统上,所以我直接使用 WSL2 环境。

我直接在 WSL2 上运行下面的安装代码:

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

然后使用 hz version v0.1.0,查看是否安装成功,就发现下面的问题,command not found

Pasted image 20230120130720.png

然后想到可能是没有正确配置好 go 的环境,也就是官网最开始提示的地方:

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

然后我这里踩了一个坑,我之前设置 GOPATH 的时候,放到了一个没有权限的目录,而且修改了 /etc/profile 文件,导致上面设置完之后重新打开一个终端就无法正常使用 hz 命令了,把 /etc/profile 修改一下上面的问题就解决了。

重新配置了环境变量之后,这个问题就解决,再重新下载安装就可以发现下面的 hz version 能正常运行了。

Pasted image 20230120131246.png

然后可以跟着官网快速创建一个 demo,因为官网写的比较详细,这里就不赘述了。

我们可以直接编译并启动 Server,出现下面的情况说明已经成功启动了。

Pasted image 20230120132719.png

然后新开一个窗口,输入 curl http://127.0.0.1:8888/ping 对接口进行测试。

Pasted image 20230120132837.png

可以发现测试成功,说明前面的安装没有问题。

Kitex 初体验

以下操作主要参考官方文档 快速开始 | CloudWeGo

首先是安装 kitex 和 thriftgo:

  1. 安装 kitex:go install github.com/cloudwego/kitex/tool/cmd/kitex@latest
  2. 安装 thriftgo:go install github.com/cloudwego/thriftgo@latest

有了前面 GOPATH 环境变量的设置,这里就容易很多,安装成功后可以查看 version。

Pasted image 20230120140957.png 下载官方提供的示例代码: git clone https://github.com/cloudwego/kitex-examples.git

然后根据官方提示直接启动:

  1. 进入示例仓库的 hello 目录 :cd kitex-examples/hello
  2. 运行 server:go run .
  3. 运行 client:另起一个终端后,go run ./client

运行结果如下:

服务端:

Pasted image 20230120141309.png

客户端:

Pasted image 20230120141339.png 接下来根据文档添加一个新的 Add 方法,最后成功运行如下:

Pasted image 20230120141852.png

Gorm 初体验

模型

Gorm 默认定义了一个结构体,包括字段 IDCreatedAtUpdatedAtDeletedAt

// gorm.Model 的定义
type Model struct {
  ID        uint           `gorm:"primaryKey"`
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt gorm.DeletedAt `gorm:"index"`
}

gorm.Model 只是官方的一个约定,具体实现可以将其嵌入到自己实现的结构体当中。

Gorm 使用的时候需要连接到数据库中,我这里用的是 MySQL,下面参考 官方文档 连接到 MySQL 中。

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

CRUD

接下来是一些简单的 CRUD 操作,我这里以一个简单的小例子为主,详细手册还是看下 官方文档

创建

首先是建立数据模型,我这里创建一个 Student 结构体,嵌套了 gorm.ModelStudent 包括两个属性姓名和成绩。

type Student struct {  
   gorm.Model  
   Name  string `gorm:"name"`  
   Grade uint   `gorm:"grade"`  
}

然后是连接到数据库,注意修改 dsn 中的数据库相关的信息:

// 参考 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{})
if err != nil {  
   panic("failed to connect database")  
}

下面我们创建一个名为 Silas,年龄 18,成绩 95 的数据,然后写入到数据库中。其中迁移的作用是自动为数据库创建一个 Student 结构体对应的表,就不需要我们手动去创建了。

// 迁移 schema
db.AutoMigrate(&Student{})

stu := Student{Name: "Silas", Age: 18, Grade: 95}  
  
result := db.Create(&stu) // 通过数据的指针来创建  
  
fmt.Println(stu.ID)              // 返回插入数据的主键  
fmt.Println(result.Error)        // 返回 error
fmt.Println(result.RowsAffected) // 返回插入记录的条数

下面是运行后截图:

Pasted image 20230120202259.png

同时也可以在 MySQL 中发现新建了一个表和一条数据:

Pasted image 20230120202350.png

为了后续查询方便,这里在添加几条数据,gorm 可以通过切片直接创建数据:

var students = []Student{{Name: "Tom", Age: 22, Grade: 98}, {Name: "Alice", Age: 19, Grade: 92}, {Name: "Bob", Age: 25, Grade: 90}}
db.Create(&students)

for _, stu := range students {
		fmt.Println(stu.ID) // 2,3,4
}

查询

GORM 提供了 FirstTakeLast 方法,以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1 条件,且没有找到记录时,它会返回 ErrRecordNotFound 错误。

result := db.First(&stu)  
fmt.Println(result)  
fmt.Println(result.RowsAffected) // 返回找到的记录数  
fmt.Println(result.Error)        // returns error  
  
// 获取一条记录,没有指定排序字段  
// SELECT * FROM students LIMIT 1;  
result = db.Take(&stu)  
fmt.Println(result)  
fmt.Println(result.RowsAffected) // 返回找到的记录数  
fmt.Println(result.Error)        // returns error  
  
// 获取最后一条记录(主键降序)  
// SELECT * FROM students ORDER BY id DESC LIMIT 1;  
result = db.Last(&stu)  
fmt.Println(result)  
fmt.Println(result.RowsAffected) // 返回找到的记录数  
fmt.Println(result.Error)        // returns error  
  
// 检查 ErrRecordNotFound 错误  
errors.Is(result.Error, gorm.ErrRecordNotFound)

Pasted image 20230120205226.png 注意上面的三条语句要分开执行,不然最后只会留下第一个查询到的数据。

Gorm 还提供了 where 子句查询,下面找到名字为 Bob 的字段:

// 获取第一条匹配的记录  
db.Where("name = ?", "Bob").First(&stu)  
fmt.Println(stu)

Pasted image 20230120204734.png

更多查询用法请见 官方文档

更新

更新一条数据,可以先获得待修改操作的对象,修改后通过 save 方法更新数据,下面代码执行过后,可以发现数据库中对应的信息已经更新了。

db.First(&stu)  

stu.Name = "silas-2"  
stu.Age = 30  
db.Save(&stu)

Pasted image 20230120210202.png

删除

删除一条记录时,删除对象需要指定主键,否则会触发 批量 Delete,例如:

// stu 的 ID 是 `1`  
// DELETE from students where id = 1; 
db.Delete(&stu) 
  
// 带额外条件的删除  
// DELETE from students where id = 1 AND name = "Silas-2";
db.Where("name = ?", "Bob").Delete(&stu)  

上面两条语句执行一条过后,Silas-2 这条数据就被删除了,但是由于 Student 结构体嵌入了 gorm.Model,此时包含了 deleted_at 字段,它获得一个软删除的能力,也就是只在 deleted_at 字段上面添加一个删除时间,但是并不实际从数据库中删除,此时也无法查询到数据。

Pasted image 20230120210805.png

可以使用 Unscoped 永久删除匹配的记录。

db.Unscoped().Delete(&stu)

小结

以上就是我作为初学者初次使用 Go 三个框架的体验,个人感觉刚开始看着比较懵,但是自己动手实践一下,发现其实并没有想像中的那么难,当然目前只是浅尝辄止,后续更深入的学习还是要多看官方文档,多写代码。