这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天。学习的三个框架为Gorm(ORM)、Kitex(RPC)、Hertz(http)。使用框架是Web开发的必要技能。
Gorm
Gorm提供与数据库交互的库。基本使用方法如下所示:
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")
}
// Migrate the schema
db.AutoMigrate(&Product{})
// Create
db.Create(&Product{Code: "D42", Price: 100})
// Read
var product Product
db.First(&product, 1) // find product with integer primary key
db.First(&product, "code = ?", "D42") // find product with code D42
// Update - update product's price to 200
db.Model(&product).Update("Price", 200)
// Update - update multiple fields
db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // non-zero fields
db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})
// Delete - delete product
db.Delete(&product, 1)
}
在规定中,Gorm的数据库名称默认为类型的蛇形命名,值的名称默认为对应的蛇形命名。要修改表名,可以添加tableName函数。
使用注解为类型提供默认值,数据库类型等信息:
type User struct {
ID int64
Name string `gorm:"default:galeone"`
Age int64 `gorm:"default:18"`
uuid.UUID UUID `gorm:"type:uuid;default:gen_random_uuid()"` // db func
}
CRUD
进行查询操作时,常用db.Where().Find()。Gorm还提供了First等方法,使用这些方法时会返回错误,需要处理。
进行更新操作时,常用db.Model().Update()。还可以使用db.Model().Select().Update()。
删除分为物理删除和软删除。
物理删除可以指定id进行删除:db.Delete(&User{}, 10)表示删除id为10的表项。使用db.Where().Delete()可以进行条件删除。
如果类型内部组合了gorm.Model,那么就可以使用Gorm的软删框架。在这种情况下,所有的删除都会变成软删除,数据不会从数据库中被删除。要想查询软删除后的字段,使用db.Unscoped().Find(),要在软删除中使用物理删除,使用db.Unscoped.Delete()。
事务
要开始一个事务,使用tx=db.Begin(),随后在tx上进行Sql操作,最后调用tx.commit()提交事务。当使用tx时,遇到错误一定要调用tx.Rollback()进行事务回滚。
Gorm还提供了db.Transaction()方法,传递一个闭包来防止程序员忘记调用tx.Rollback()。在闭包里不需要调用tx.Rollback(),建议使用。
Hook
Hook是在CRUD之前或之后自动调用的函数。
使用func(*u User)BeforeCreate(tx gorm.DB)(err error)或AfterCreate添加Hook。
Gorm性能提高
对于写操作,Gorm会默认封装在事物中运行。为了提高性能,可以调用SkipDefaultTransaction.
使用PrepareStmt缓存预编译语句可以提高后续调用的速度,约为35%。
Gorm生态
| 工具名 | 工具 |
|---|---|
| 代码生成 | gen |
| 分片库 | sharding |
| 手动索引 | hints |
| 乐观锁 | optimisticlock |
| 读写分离 | dbresolver |
| OpenTelementry扩展 | opentelementry |
Kitex
使用IDL定义服务和接口(Thrift、Proto3)。使用Kitex可以根据thrift生成代码kitex -module <NAME> -service <NAME> <NAME>.thrift。
Kitex生成代码默认监听8888端口。客户端调用:
for {
req := &api.Request{Message: "my request"}
resp, err := client.Echo(context.Background(), req)
if err != nil {
log.Fatal(err)
}
log.Println(resp)
time.Sleep(time.Second)
}
Kitex扩展
| 工具名 | 工具 |
|---|---|
| XDS扩展 | kitex-contrib/xds |
| opentelemetry扩展 | /obsopentelemetry |
| ECTD服务注册与发现 | /registry-ectd |
| ... | ... |
Hertz
Hertz是一个高性能的Web框架
g := server.Default(server.WithHostPorts("127.0.0.1:8080"))
h.Get("/ping", func(c context.Context, ctx *app.RequestContext)) {
ctx.JSON(consts.StatusOK, utils.H{"ping" : "pong"})
}
h.Spin()
使用h.+GET POST PUT DELETE等方法进行路由。
参数绑定:
中间件是一个app.HandleFunc,基本流程为:
func(c context.Context, ctx *app.RequestContext) {
// pre-handle
c.next(ctx)
// post-handle
}
使用h.Use(f())调用中间件。
Hertz也支持客户端。可以使用Hertz的客户端方便地发送请求。
Hertz也支持通过IDL生成基础服务代码。代码工具为Hz。