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

540 阅读10分钟

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

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

零、前言:

鉴于官方文档的齐全性,本文对于框架三件套的细节没有做过多的记录,只是记录一些重要的概念和内容,后续会补充上本人在实际操作和运用这三个框架时的debug历程,我认为这是比单纯复制知识点更加高效的学习方式,那么我们开始吧!

本文记录和整理了本人在跟随字节青训营学习的一些我个人感觉比较重要的内容和知识,也有一部分内容是我认为自己比较难理解或记忆的,也一并记录于此文。 撰写本文的目的主要是方便我自己的复习和查阅,倘若各位读者有与我相似的问题,也可以参考之,如果对各位有帮助那就是我莫大的荣幸,也期望各位不吝赐教,多多指出我的问题,可以在下方留言或者私信我。


一、本堂课重点内容:

  • 将前面几节课所学到的知识应用到项目中
  • 掌握Hertz / Kitex / Gorm的基本用法
  • 通过学习实战案例,可以使用Hertz / Kitex / Gorm完成日常后端开发任务

二、详细知识点介绍

0. 背景知识扫盲

对于这部分知识熟悉的朋友可以选择跳过

这一部分可能对于细节的解释不够严谨和充分,只是为了方便后文引入概念,如果有任何不明确的地方可以自行查找。

什么是数据库和SQL?

数据库,即Database,是将大量数据保存起来,通过计算机加工而成的可以进行高效访问数据集合

SQL,即Structured Query Language,结构化查询语言,是用来操作关系数据库的语言。

SQL的语句及其种类

  1. DDL(Data Definition Language,数据定义语言)用来创建或者删除存储数据用的数据库以及数据库中的表等对象。 DDL 包含以下几种指令。

    1. CREATE: 创建数据库和表等对象
    2. DROP: 删除数据库和表等对象
    3. ALTER: 修改数据库和表等对象的结构
  2. DML(Data Manipulation Language,数据操纵语言)用来查询或者变更表中的记录。 DML 包含以下几种指令。

    1. CREATE: 创建数据库和表等对象
    2. DROP: 删除数据库和表等对象
    3. ALTER: 修改数据库和表等对象的结构
  3. DCL(Data Control Language,数据控制语言)用来确认或者取消对数据库中的数据进行的变更。除此之外,还可以对 RDBMS 的用户是否有权限操作数据库中的对象(数据库表等)进行设定。 DCL 包含以下几种指令。

    1. COMMIT: 确认对数据库中的数据进行的变更
    2. ROLLBACK: 取消对数据库中的数据进行的变更
    3. GRANT: 赋予用户操作权限
    4. REVOKE: 取消用户的操作权限

SQL的基本书写规则:

    1. SQL语句要以分号(;)结尾;
    2. SQL语句不区分关键字大小写,插入表中的数据区分大小写
    3. 常数的书写方式是固定的,字符串和日期常数需要使用单引号(')括起来,数字常数无需加注单引号(直接书写数字即可);
    4. 单词间需要用半角空格或者换行来分隔,不能使用全角空格作为单词的分隔符;

其他的有关内容和细节还可以参考我的博客:学习记录丨MySQL入门 | 落雨乄天珀夜 (gitee.io)


什么是DSN?

DSN是数据源名称Data Source Name,是应用程序用来请求与ODBC数据源连接的名称。连接到ODBC时,它会存储连接详细信息,例如数据库名称、目录、数据库驱动程序、UserID、password等。


什么是ORM?GORM又是什么?

ORM全称是:Object Relational Mapping(对象关系映射),其主要作用是在编程中,把面向对象的概念跟数据库中表的概念对应起来。

举例来说就是,我定义一个对象,那就对应着一张表,这个对象的实例,就对应着表中的一条记录。

GORM:是Golang语言中一款性能极好的ORM库,对开发人员相对是比较友好的。

GORM特性

  • 全功能 ORM
  • 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
  • Create,Save,Update,Delete,Find 中钩子方法
  • 支持 PreloadJoins 的预加载
  • 事务,嵌套事务,Save Point,Rollback To Saved Point
  • Context、预编译模式、DryRun 模式
  • 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
  • SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
  • 复合主键,索引,约束
  • Auto Migration
  • 自定义 Logger
  • 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
  • 每个特性都经过了测试的重重考验
  • 开发者友好

GORM安装

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

Quick Start

package main

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

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

func main() {
  db, err := gorm.Open(sqlite.Open("test.db"), &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)
}

更细节的操作可以参考:GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.

什么是Kitex?

Kitex是字节内部的Golang微服务PRC框架。

什么是Hertz?

Hertz是字节内部的HTTP框架。


1. 理解Database / SQL

设计原理

avatar

可以使用import driver实现,使用driver + DSN初始化DB连接

需要注意连接池配置 & 连接池状态;

Driver连接接口;

DB连接的几种类型

  • 直接连接 / Conn
  • 预编译 / Stmt
  • 事务 / Tx

处理返回数据的几种方式

  • Exce / ExceContext -> Result
  • Query / QueryContext -> Rows (Columns)
  • QueryRow / QueryRowContext -> Row (Rows简化)

2. GORM使用简介

这一部分的详细内容依然可以参考:GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.

模型定义

模型是标准的struct,由 Go 的基本数据类型、实现了 Scanner 和 Valuer 接口的自定义类型及其指针或别名组成。

// 一个例子
type User struct {
  ID           uint
  Name         string
  Email        *string
  Age          uint8
  Birthday     *time.Time
  MemberNumber sql.NullString
  ActivatedAt  sql.NullTime
  CreatedAt    time.Time
  UpdatedAt    time.Time
}

gorm.Model可以嵌入在已有的结构体中,还可以进行权限控制;

模型的一些惯例约定:

avatar

连接到数据库

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

我们就以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.New(mysql.Config{
  DSN: "gorm:gorm@tcp(127.0.0.1:3306)/gorm?charset=utf8&parseTime=True&loc=Local", // DSN data source name
  DefaultStringSize: 256, // string 类型字段的默认长度
  DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
  DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
  DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
  SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
}), &gorm.Config{})
}

关于连接池

连接池是什么?

连接池是创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用。

连接池有什么好处

  • 减少连接创建时间
  • 简化的编程方式
  • 受控的资源使用

GORM使用Database / SQL来维护连接池;

sqlDB, err := db.DB()

// SetMaxIdleConns 设置空闲连接池中连接的最大数量
sqlDB.SetMaxIdleConns(10)

// SetMaxOpenConns 设置打开数据库连接的最大数量。
sqlDB.SetMaxOpenConns(100)

// SetConnMaxLifetime 设置了连接可复用的最大时间。
sqlDB.SetConnMaxLifetime(time.Hour)

基本用法-CRUD

创建 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.

关联

Belongs To | GORM - The fantastic ORM library for Golang, aims to be developer friendly.

3. GORM设计原理

此部分待补充

  • SQL生成
  • 插件扩展
  • ConnPool
  • Dialector

4. GORM最佳实践

avatar


5. Kitex相关内容

温馨提示:Kitex目前对Windows的支持不完善,如果本地开发环境是Windows建议使用虚拟机orWSL2;

安装代码生成工具

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

查看版本:

~ % kitex -version

定义IDL

IDL是什么?

IDL是Interface description language的缩写,指接口描述语言,是规范的一部分,是跨平台开发的基础。

RPC是什么:

RPC(Remote Procedure Call Protocol)远程过程调用协议。一个通俗的描述是:客户端在不知道调用细节的情况下,调用存在于远程计算机上的某个对象,就像调用本地应用程序中的对象一样。比较正式的描述是:一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。

// 使用IDL定义服务与接口
/*
如果我们要进行PRC,就需要知道对方的接口是什么,需要传什么参数,同时也需要知道返回值时什么样的,这个时候,就需要通过IDL来约定双方的协议,就像在写代码的时候需要调用某个函数,我们需要知道函数签名一样。
*/
// Thrift: https://thrift.apache.org/docs/idl
// Proto3: https://developers.google.com/protocol-buffers/docs/proto3

namespace go api

struct Request {
    1: string message
}

struct Response {
    1: string message
}

service Echo {
    Response echo(1: Request req)
}

Kitex生成代码

具体可以参考http://www.cloudwego.io/zh/docs/kitex/getting-started/

使用如下命令生成代码:

kitex -module example -service example echo.thrift

文件说明:

  • build.sh:构建脚本
  • kitex_gen:IDL内容相关的生成代码,主要是基础的Server/Client代码
  • main.go:程序入口
  • handler.go:用户在该文件里实现IDLservice定义的方法

服务默认监听8888端口;

Kitex Client发起请求:

  • 创建Client
  • 发起请求

Kitex服务注册与发现:

目前Kitex的服务注册与发现已经对接了主流的服务注册与发现中心,如ETCD,Nacos等;

Kitex生态:

详见:https://www.cloudwego.io/zh/docs/kitex/


6. Hertz相关内容

详细内容可以查看:https://www.cloudwego.io/zh/docs/hertz/getting-started/

Hertz路由

Hertz提供了GET、POST、PUT、DELETE、ANY等方法用于注册路由;

提供了路由组Group的能力,用于支持路由分组功能;

提供了参数路由和通配路由,路由的优先级为:静态路由 > 命名路由 > 通配路由

Hertz参数绑定

Hertz提供了Bind、Validate、BindAndValidate函数用于进行参数绑定和校验;

Hertz中间件

Hertz的中间件主要分为客户端中间件与服务端中间件;

Hertz Client

Hertz提供了HTTP Client用于帮助用户发送HTTP请求;

Hertz代码生成工具

Hertz提供了代码生成工具Hz,通过定义IDL文件即可生成对应的基础服务代码;


三、项目实践环节

项目介绍:

笔记项目是一个使用Hertz、Kitex、Gorm搭建出来的具备一定业务逻辑的后端API项目。

服务名称服务介绍传输协议主要技术栈
demoapiAPI服务HTTPGorm/Kitex/Hertz
demouser用户数据管理ProtobufGorm/Kitex
demonote笔记数据管理ThriftGorm/Kitex

项目模块:

demoapi:

  • 用户登录
  • 用户注册
  • 用户创建笔记
  • 用户更新笔记
  • 用户删除笔记
  • 用户查询笔记

demouser:

  • 创建用户
  • 查询用户
  • 校验用户

demonote:

  • 创建笔记
  • 更新笔记
  • 删除笔记
  • 查询笔记

此部分可能后续会单独撰写一篇文章,敬请期待...


未完待续...(随时补充修改)

谢谢大家的阅读,欢迎互动,也欢迎访问我的博客!

conqueror712.github.io/