这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天
Gorm
- 基本操作
package main
import (
"gorm.io/gorm"
"gorm.io/driver/sqlite"
)
type Product struct {
Code string
Price uint
}
func (p Product) TableName() string {
return "product"
}
func main() {
db, err := gorm.Open(
mysql.Open("user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"),
&gorm.Config{})
if err != nil {
panic("failed to connect database")
}
// 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)
}
-
可以用clause.OnConflict 处理数据冲突情况 如:
p := &Product{Code: ''D42", ID:1}db.Clauses(clause.OnConflict{DoNothing: true}).Create(&p)此为不处理冲突,直接插入
-
查询:用First 和 Where + Find 进行查询,业务开发中一般用后者,前者在没有数据的时候会返回Error,而后者只是返回空数组
-
在用
struct进行查询时,零值将不会被列入查询条件中;用map可以解决这个问题// SELECT* FROM users WHERE name ="jinzhu"; db.Where(&User{Name:"jinzhu",Age: 0).Find(&users) // SELECT * FROM users WHERE name ="jinzhu" AND age = 0; db.Where(map[string]interface{}{"Name":"jinzhu","Age": 0)).Find(&users) -
更新:除了能用
Select()选择只更新的字段,其他同上,这样看起来平常使用map能防止一些不必要的错误 -
gorm提供了一种表达式更新
// SQL 表达式更新 // UPDATE "products" SET "price" = price * 2 + 100"updated at : 2013-11-17 21:34:10' WHERE "id" = 3 db.Model(&User{ID: 111)).Update( column: "age", gorm,Expr( expr: "age * ? + ?", args... 2, 100)) -
删除:使用 Where + delete 即可,但除了这种物理删除,GORM也提供了 gorm.DeleteAt 来进行软删除,可通过Unscoped 来进行恢复.
type User struct {
ID int64
Name string `gorm:"default:galeone"`
Age int64 `gorm:"default:18"`
Deleted gorm.DeletedAt
}
- 事务:使用Begin开启一个连接,此时使用Begin返回的变量tx,而非调用的db;使用Rollback回滚,Commit提交;当然Gorm也提供了
Transaction来开启自动提交事务;包括Hook SkipDefaultTransaction false关闭默认事务PrepareStmt true开启预编译- GORM生态非常丰富,包括且不限于锁,读写分离,索引等等. 这些去官方文档可以查到很多
Kitex
- 基于IDL:在 RPC 框架中,我们知道,服务端与客户端通信的前提是远程通信,但这种通信又存在一种关联,那就是通过一套相关的协议(消息、通信、传输等)来规范,但客户端又不用关心底层的技术实现,只要定义好了这种通信方式即可。
package main
import (
"context"
'example/kitex_gen/api"
)
// EchoImpl implements the last service interface defined in the IDL
type EchoImpl structf{}
// Echo implements the EchoImpl interface .
func (s *EchoImpl) Echo(ctx context.(ontext, reg *api.Request) (resp *api.Response, err error) {
// TODO: Your code here ...
return
}
- 同样,Kitex也拥有非常多的扩展,ETCD,Nacos等服务注册,具体可以去官网查看文档
Hertz
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/common/utils"
"github.com/cloudwego/hertz/pkg/protocol/consts"
)
func main() {
h := server.Default()
h.GET("/ping", func(c context.Context, ctx *app.RequestContext) {
ctx.JSON(consts.StatusOK, utils.H{"message": "pong"})
})
h.Spin()
}
- 路由:
-
- Hertz提供了GET,POST,DELETE,PUT,PATCH等路由注册,也拥有路由组(Group)的功能,用于支持路由分组的功能,同时中间件也可以注册到路由组上
- 三种路由类型优先级: 静态 > 命名 > 通配
- 函数 :Hertz 提供了 Bind、Validate、BindAndValidate 函数用于进行参数绑定和校验
个人总结
今天课程讲了开发三大件GORM 数据库映射,Kitex RPC框架,Hertz http框架,虽然我们项目用的是go-zero,但也能从类似框架上看到一样的模式,课程中结合实战的例子讲了这几个框架的串联,将整个项目的技术栈串联起来,给人更有实际开发的流程感觉.