数据库创建, 模板生成以及流程梳理
在上一节的流程图中,我们设置了三个端,分别是客户端,商家端和运营端。
客户端
⽤户在订单到达指定状态后可以对订单发表评价。可以对订单进行评论打分,商品信息,商家是否有回复等。因此需要有订单id,店铺id,用户id等
商家端
保存商家后台对⽤户发表评价的回复。因此需要有回复id,订单id,店铺id等。
运营端
商家可对⽤户提交的评价进⾏申诉,⽐如⽤户提交的评价中出现其他品牌⼴告或要挟商家等恶意评价内容。运营端可以对评论进行处理。因此需要有评论id,店铺id,申诉id,回复id等。
数据库分表
当数据量过大的时候,单表数据库访问就会导致时间过长。因此可以用到垂直分表和水平分表。
垂直分表:将表进行拆分,将将不常⽤字段或占⽤空间较⼤的字段拆分出去,例如,关键的摘要数据与⼤篇幅内容分表存储等。
水平分表:将表中某个字段进行拆分,例如,电商场景下按⽤户或店铺维度进⾏分表。
具体按什么分表也是根据业务场景来决定的。
例如:购物⻋⼀般按⽤户分表,商品信息按商家分表。想⼀想,为什么?
将购物⻋⽔平拆分成100张表,cart_info_00~cart_info_99 , user_id:176003, 176003%100=3 =>
cart_info_03'
接下来我们使用gorm/gen
将model
层。教程
简单来说,他会:
- 基于原始SQL语句生成可重用的CRUD API
- 生成不使用interface{}的100%安全的DAO API
- 依据数据库生成遵循GORM约定的结构体Model
- 支持GORM的所有特性
先创建新项目
kratos new review-service
我们在数据库中建完表之后,在/cmd/gen
中添加生成代码generate.go
。
var flagconf string
func init() {
flag.StringVar(&flagconf, "conf", "../../configs", "config path, eg: -conf config.yaml")
}
func connectDB(cfg *conf.Data_Database) *gorm.DB {
if cfg == nil {
panic(errors.New("GEN: connectDB fail, need cfg"))
}
switch strings.ToLower(cfg.GetDriver()) {
case "mysql":
db, err := gorm.Open(mysql.Open(cfg.GetSource()))
if err != nil {
panic(fmt.Errorf("connect db fail: %w", err))
}
return db
case "sqlite":
db, err := gorm.Open(sqlite.Open(cfg.GetSource()))
if err != nil {
panic(fmt.Errorf("connect db fail: %w", err))
}
return db
}
panic(errors.New("GEN:connectDB fail unsupported db driver"))
}
func main() {
flag.Parse()
//为了避免每次修改连接地址都要修改代码,选择从配置文件中加载
c := config.New(
config.WithSource(file.NewSource(flagconf)))
defer c.Close()
if err := c.Load(); err != nil {
panic(err)
}
//将配置加载并绑定结构体
var bc conf.Bootstrap
if err := c.Scan(&bc); err != nil {
panic(err)
}
创建构造器
g := gen.NewGenerator(gen.Config{
OutPath: "../../internal/data/query",
Mode: gen.WithDefaultQuery | gen.WithQueryInterface,
FieldNullable: true, // delete_at是可以为空的
})
g.UseDB(connectDB(bc.Data.Database))
//生成所有表的crud,也可以自己选择创建哪张表
g.ApplyBasic(g.GenerateAllTable()...)
// 执行并生成代码
g.Execute()
}
值得注意Mode:gen.WithDefaultQuery | gen.WithQueryInterface,
Mode
当我们使用
gen.WithDefaultQuery
这个会生成一个全局变量Q,这样我们在不同的包里就没有必要重复编写g.UseDB(connectDB(bc.Data.Database))
。最后运行代码于
data
包下生成代码。生成的
model
存放结构体,query
存放查询函数。
//Query.go
//可以看到这里面有个db,当我设置有gen.WithDefaultQuery 时会生成。
var (
Q = new(Query)
ReviewAppealInfo *reviewAppealInfo
ReviewInfo *reviewInfo
ReviewReplyInfo *reviewReplyInfo
)
type Query struct {
db *gorm.DB
ReviewAppealInfo reviewAppealInfo
ReviewInfo reviewInfo
ReviewReplyInfo reviewReplyInfo
}