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

113 阅读4分钟

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

本堂课的重点

  • Gorm
  • Kitex
  • Hertz

Gorm

Gorm是一个已经迭代了10年+的功能强大的ORM框架,在字节内部被广泛 使用并且拥有非常丰富的开源扩展。

Gorm的约定(默认)

  • Gorm使用名为ID的字段作为主键
  • 使用结构体的蛇形负数作为表名1929
  • 字段名的蛇形作为列名
  • 使用CreatedAt、UpdatedAt字段作为创建、更新时间

Gorm支持的数据库

支持MYSQL、SQLServer、PostgreSQL、SQLite 下面是MYSQL实例:

import (
"gorm.io/driver/sqlserver"
"gorm.io/gorm"
}
// github . com/denisenkom/ go-mssqldb
dsn := "sqlserver: // gorm: LoremIpsum86@localhost:9930?database=gorm"db,err := gorm.Open(sqlserver.0pen(dsn),&gorm.Config)

Gorm 创建数据

1.连接数据库 2.创建结构数据 3.db.Create(数据)

impor {
"fnt"
"gorm.io/driver/mysql"
"gorm.io/gorn"
}
tyre Product struct {
ID uint `gorm: "primarykey"`
Code string  `gorm: "column:code"`
Price uint `gorm: "column:user_id"`
}
furc main( {
db.err := gonm.open(mysql.open ( dsn :"username: passwardl@tco(localhest:9910)/database?charset=utf8"),
&gorm.Config{})
if err != nil : 
    "failet to connect database"
 //创理一条
p: = &Product{code: "042"]
res := db.Create(p)
fmt.Print1n(res .Error) /获取err
fmt.Println(p.ID)/返回插入数据的主键
//创建多条
products := [ ]*Product{{Code: “041"},Code:“042""],{Lode:“063“}}
res = db.Create(products)
fmt.Println(res.Error)//获取err 
    for _,p : = range products {
fmt.Println(p.ID)
}

注意:使用clause.OnConflict处理数据冲突;通过使用default标签为字段定义默认值

Gorm 查询数据

First和Find两种方法

db,err := gorm.open(mysql.Open( dsn: "username:passwordl@tep(localhost:9910)/database?charset=utf8"),
&gorm.Config{})
if err != nil {
    panic( v: "failed to connect database")
}
//获取第一条记录〔主键升序),查询不到数据则返回ErrRecordNotFoundu
u := &User{科
db.First(u) // SELECT * FRON users 0RDER BY id LIMIT 1;
//查询多条数据
users: = make([]*User,0)
result := db.Where( query: "age > 10").Find(&users) // SELECT * FRON users where age > 18;
fmt.Println(result.RowsAffected)
fmt.Println(result.Error)
// returns error
// IN SELECT * FROM users WHERE name IN (' jinzhu', "jinzhu 2');
db.Where( query: "name IN ?",[]string{"jinzhu"”,"jinzhu 2")}.Find(&users)
// LIKE SELECT * FRON users WHERE name LIKE '%jin%';
db.Where( query: "name LIKE ?" , args..:“%jin%"").Find(&users)
// AND SELECT * FRDN users WHERE name = 'jinzhu’ AND age >= 22;
db.Where( query: "name = ? AND age >= ?",args...:"jinzhu","22"").Find(&users)
 //SELECT * FROM users WHERE name = “jinzho";29
db.Where(&User{Name : "jinzhu", Age : 0).Find(&users)
//SELECT * FRDM users WHERE name = "jinzhu” AND age = 0;
db.where(map[string]interface(}{ " Name" : "jinzhu",“Age":9}).Find(tusers)

注意:使用 First时,需要注意查询不到数据会返回ErrRecordNotFound。 使用 Find查询多条数据,查询不到数据不会返回错误。

Gorm 更新数据

db.Model()

//条件更新单个列
//UPDATE users SET name= ' hello ' ,updoted_at='2813-11-17 21:34:18’ WHERE oge > 18;
db.Mode1(&lUser{ID: 111),Where( query: "age > ?",arg.….:18 ). Update( column: "name",value: "he1lo")
//更新多个列
//根据‘struct’更新属性,只会更新非零值的字段
//UPDATE users SET nome=' hello ', age=18,updated_at = '2813-11-17 21∶34:16'’VWHERE id = 111
db.Model(&User{ID: 111}).Updates(User{Name : "hello",Age: 18}]
//根据‘map’更新属性
//UPDATE users SET nome='hello' ,age=18,gctived=folse,updated_at='2813-11-17 21:36:10’ WHERE id=111;
db.Mode1(&User{ID: 111)).Updates(map[string]interface{}{ "name" : "hello","age":18"actived": false})
//更新选定字段
// UPDATE users SET name= 'hello' WHERE id=111;
db.Model(&User{ID: 1111).Select( query : " name".Updates(map[string]interface{}{"name" ; “hello",
"age" : 18, "actiyed" : false})
// sQL表达式更新
//UPDATE “products" SET“price" = price * 2 + 188,“updated_at"= '2813-11-17 21:36:10’WHERE“id”= 3;
db.Model(&User{ID: 111}).Update( column:"age " ,gorm.Expr ( expr: " age * ? + ?" , arg …: 2 ,100))

注意:使用 Struct 更新时,只会更新非零值,如果需要更新零值可以使用Map更新或使用Select选择字段。

Gorm 删除数据

物理删除和软删除

db.Delete(&User},conds.:10)// DELETE FROM users WHERE id = 18;
db.Delete(&User(,conds...:"10")// DELETE FRON users WHERE id = 10;
db.Delete(&Useri},[]int{123})//DELETE FRON users WHERE id IN (1,2,3);
db.Where( query: " name LTKE ?",arg .….…"%jinzhu%").Delete(User{})//DELETE from users where name LIKE “%jinzhu8"";
db.Delete(Userf,conds.: "email LITKE ?""%jinzhu%")// DELETE from users where name LIKE“%jinzhu%" ;

GORM提供了gorm.DeletedAt 用于帮助用户实现软删 拥有软删除能力的Model 调用Delete时,记录不会被从数据库中真正删除。但 GORM会将DeletedAt置为当前时间,并且你不能再通过正常的查询方法找到该记录。 使用Unscoped可以查询到被软删的数据

Kitex

Kitex是字节内部的Golang微服务RPC框架,具有高性能、强可扩展的主要特点,支持多协议并且拥有丰富的开源扩展。

定义IDL

接口的定义,方便我们去调用

namespace go api
struct Request i
    1: string message
}
struct Response {
    1: string message}
service Echo i
    Response echo(1: Request req)
}

使用kitex -module example -service example echo.thrift命令生成代码

Kitex Client 发起请求

创建Client

import "example/kitex_gen/api/echo"
import "github.com/cloudwego/kitex/client"
...
c, err := echo .NewClient( "example", client.WithHostPorts("0.0.0.0:8888"))
if err != nil {
    log. Fatal(err)
}

发起请求

import "example/kitex_gen/api"929
...
req := &api . Request{Message: "my request"}
resp,err := c.Echo(context. Background(),req, callopt.WithRPCTimeout(3*time. Second))
if err != nil {
    log. Fatal(err)
}
log . Println(resp)

Hertz

Hertz是字节内部的HTTP框架,参考了其他开源框架的优势,结合字节跳动内部的需求,具有高易用学习性、高性能、高扩展性特点。

Hertz路由

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

image.png 通配路由(范围比参数路由广)

image.png

Hertz中间件

Hertz的中间件主要分为客户端中间件与服务端中间件,如下展示一个服务端中间件。

func MyMiddleware() app.HandlerFunc {
    return func(ctx context.Context, c *app.RequestContext) { 
        // pre-handle
        fmt.Printin( a...: "pre-handle")
        c.Next(ctx) //call the next middleware(handler)
        // post-handle
        fmt.Println( a...:"post-handle")
    }
}
func main() {
h := server.Default(server.WithHostPorts( hp: "127.0.0.1:8080"))
h.Use(MyMiddleware() )
h.GET( relativePath: " /middleware"func(ctx context.Context,c *app.RequestContext){
    c.String(consts.StatusOk,format: "Hello hertz! ")
    })
h.Spin()
}

个人总结

经过这一天的学习,我学习到GO语言中框架的使用,例如Gorm、Hertz、Kitex