go框架三件套(Web/RPC/ORM)| 青训营笔记

112 阅读4分钟

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

本节课的重点内容如下:

  1. GORM框架的基本CRUD、事务、钩子函数等
  2. Kitex框架的基本使用、IDL语言、其代码生成等
  3. Hertz框架的基本使用
  4. 学习实战案例——笔记项目的写法

go框架三件套(Web/RPC/ORM)

GORM(ORM框架)

GORM 倾向于约定,而不是配置。默认情况下,GORM 使用 ID 作为主键,使用结构体名的 蛇形复数 作为表名,字段名的 蛇形 作为列名,并使用 CreatedAtUpdatedAt 字段追踪创建、更新时间

例子:

 type User struct {
   ID           uint                 // 主键id
   Name         string               // name
   Email        *string              // email
   Age          uint8                // age
   Birthday     *time.Time           // birthday
   MemberNumber sql.NullString       // member_number
   ActivedAt    sql.NullTime         // actived_at
   CreatedAt    time.Time            // created_at
   UpdatedAt    time.Time            // updated_at
 }

1、基本的CRUD

1)获取db连接

db, err := gorm.Open(mysql.Open(DSN),&gorm.Config())

其中DSN,指的是Data Source Name,需要填入指定格式的参数

格式: [username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]

例子: user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local

2)查询

将结构体与表名相绑定
 // 这个结构体用于映射表属性
 type Student struct {
    Id int64     // id 默认为主键
    Name string  // name
    Tutor int64  // tutor
 }
 // 这个方法就用于绑定表名
 func (student Student) TableName() string {
    return "student"
 }
简单查询语句

db.First(&student) 默认按照主键升序排序,取出第一条记录

相当于 select * from student order by student.Id limit 1

例子:

 var student Student
 db.First(&student) // select * from student order by student.Id limit 1
 fmt.Println(student)
 ​
 student = Student{}
 db.First(&student, 4) // select * from student where id = 4 order by ...
 fmt.Println(student)
 ​
 student = Student{}
 db.First(&student, "id = ?", 3) // select * from student where id = 3 order by 
 fmt.Println(student)

db.Take(&student) 获取一条记录,没有指定排序字段 相当于 SELECT * FROM student LIMIT 1;

db.Last(&student) 获取最后一条记录,按照主键降序排序 相当于SELECT * FROM student ORDER BY student.id DESC LIMIT 1;

复杂查询

GORM采用的是一种链式调用的方式,所以可以很方便的去拼接查询条件,但在Find()之后拼接的条件不会再生效

 students := make([]*Student, 0)
 db.Where("name = ?", "王五").Find(&students)
 for _, std := range students {
    fmt.Println(*std)
 }
 // {3 王五 3}
 ​
 fmt.Println()
 db.Where("id > ? and tutor <= ?", 3, 5).Find(&students)
 for _, std := range students {
    fmt.Println(*std)
 }
 // {4 赵六 4}
 // {5 田七 5}

3)增加

db.Create(&nStudent) 向数据库中添加指定的数据

 nStudent := Student{Id: 666, Name: "niubi", Tutor: 777}
 result := db.Create(&nStudent)
 fmt.Println(result.Error)
 fmt.Println(result.RowsAffected)

4)更新

db.Model(&User{ID: 111}).Where("age > ?", 6666).Update("name", "hello")

// update user set name = "hello" where age > 6666 and id = 111

其中Model主要是用来通过结构体来传入表名,同时还可以将其属性作为兜底的where条件(会作为where条件来使用),一般的用法 Model(&结构体对象的引用{})

为什么要使用Model(&User{})?

我个人的想法是,更新语句是通过Update(column, value),来执行实际的 set column = value,也就是说Update中不带有任何可以判定目标表名的条件,所以就需要Model来作为一个补充,帮助传入表名

image-20230117102915189

5)删除

image-20230117103349161

2、事务

image-20230117104039364

image-20230117104211866

3、钩子函数Hook

Kitex(RPC框架)

1、IDL(接口定义语言,用来定义接口参数、返回值等)

image-20230117110558804

struct Request 和 struct Response 结构体就相当于该RPC接口的请求与响应结构

service Echo:指明该服务的名称为Echo,其中有一个接口叫echo,能够接收Request类型的参数,响应值为Response类型

2、Kitex生成的代码结构

Kitex自带代码生成工具,在编写好服务对应的IDL文件(可以是thrift类型,也可以是proto类型)之后,就可以通过相应的指令来自动生成代码

kitex -module example -service example echo.thrift

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

3、对接服务注册中心,获取服务对象

普通的传入服务地址

hello.NewClient("hello", client.WithHostPorts("0.0.0.0:8888")) 传入服务实例地址

对接服务注册中心

hello.NewClient("hello", client.WithResolver(r)) 传入注册中心,通过注册中心来获取服务实例

image-20230117111628958

Hertz(Web框架)

Hertz是一个 Golang 微服务 HTTP 框架,在设计之初参考了其他开源框架 fasthttpginecho 的优势, 并结合字节跳动内部的需求,使其具有高易用性、高性能、高扩展性等特点

1、路由操作(与gin类似)

注册路由

image-20230117112305599

参数路由和通配路由

image-20230117112424733

参数路由如果请求没有提供参数,就无法匹配,无法无视参数

通配路由如果请求没有提供参数,可以匹配,相当于忽视了参数段 —— 所以应该更加常用?

例子(可以看出与Gin的使用及其相似)

 // 使用gin
 r := gin.Default()   
 // 配置路由
 r.GET("/page/get/:id", func(c *gin.Context) {
     topicId := c.Param("id")
     data := controller.QueryPageInfo(topicId)
     c.JSON(200, data)
 })
 err = r.Run()   // 启动服务
 if err != nil {
     return
 }
 ​
 // 使用Hertz
 h := server.Default()   // 启动服务
 // 配置路由
 h.GET("/page/get/:id", func(c context.Context, ctx *app.RequestContext) {
    topicId := ctx.Param("id")
    data := controller.QueryPageInfo(topicId)
    ctx.JSON(200, data)
 })
 h.Spin()    // 启动服务

2、参数绑定(自动填充参数,不用自己取)

这里定义了一个Args结构体,其中结构体的每个属性都与一个参数相对应

当调用 c.BindAndValidate(&args)时,herz框架会自动将请求中的对应属性填充进args中

3、中间件(不知道这里的中间件是什么概念)

image-20230117113201287

实战案例

项目功能介绍

image-20230117114148146

image-20230117114240095

没写了,记录一下笔记项目的地址,自己留着看代码

github.com/cloudwego/k…