之前在字节实习的时候,由于业务分层较细,我们团队负责的属于较上层,并没有接触到数据库的 ORM 代码编写。这次在 B 站实习是中台,会接触到较复杂的 ORM SQL 代码编写。所以记录以下 ORM 查询模板
Option 模式(自己项目的方式)
dao 层
1
2
3
4
5
6
7
8
|
// project/dao/dao.go
type Client struct {
musicOrm *gorm.DB // 一个数据库一个客户端,当然里面其实里面是有连接池的
videoOrm *gorm.DB
proxyOrm *gorm.DB
}
type Option func(*gorm.DB) *gorm.DB
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
// project/dao/music.go
type MusicDao struct {
*Client
}
func (dao *MusicDAO) GetMusic(ctx context.Context, opts ...Option) (*model.Music, error) {
db := dao.musicOrm.DB.WithContext(ctx)
for _, opt := range opts {
db = opt(db)
}
var music model.Music
return &music, db.First(&music).Error
}
// Options
func (MusicDAO) WithID(id uint) Option {
return func(d *gorm.DB) *gorm.DB {
return d.Where("id = ?", id)
}
}
func (MusicDAO) WithStatus(status int32) Option {
return func(d *gorm.DB) *gorm.DB {
return d.Where("status = ?", status)
}
}
|
使用
1
2
3
4
5
6
7
8
|
// project/service
type Service struct {
musicDao *MusicDao
}
func (s *Service) GetMusic(ctx context.Context, id uint, status int32) (*model.Music, error) {
return s.musicDao.GetTime(ctx, s.musicDao.WithID(id), s.musicDao.WithStatus(status))
}
|
参数模式(B 站项目)
dao 层
1
2
3
4
5
6
|
// project/dao/dao.go
type Dao struct {
musicOrm *gorm.DB
videoOrm *gorm.DB
proxyOrm *gorm.DB
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
// project/dao/music.go
// 全部都是直接在 Dao 层下,粒度较大,这点要批评,建议和上面一样 Dao 下面再分 MusicDao
func (dao *Dao) GetMusic(ctx context.Context, where string, params ...interface{}) (music *model.Music, err error) {
db := dao.musicOrm.DB.WithContext(ctx)
err = db.Model(&model.Music{}).Where(where, params...).First(music).Error
return
}
func (dao *Dao) GetMusics(ctx context.Context, offset, limit int, orderby, where string, params ...interface{})(musics []*model.Music, err error) {
orm := dao.musicOrm.Where(where, params...)
if orderby == "" {
orderby = "id desc"
}
orm = orm.Order(orderby)
if limit > 0 {
orm = orm.Limit(limit)
}
if offset > 0 {
orm = orm.Offset(offset)
}
if err = orm.Find(&musics).Error; err != nil {
return
}
return
}
|
使用层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// project/service
type Service struct {
dao *Dao
}
func (s *Service) GetMusic(ctx context.Context, id uint, status int32) (*model.Music, error) {
var (
wheres []string
params []interface{}
)
if id != 0 {
wheres = append(wheres, "id = ?")
params = append(params, id)
}
if status != 0 {
wheres = append(wheres, "status = ?")
params = append(params, status)
}
// 注意要 ...params !!!
return s.dao.GetMusic(ctx, strings.Join(wheres, " AND "), ...params)
}
|
总结
Option 方式对于同一个查询条件,复用程度高,但 where params 的方式更加灵活,由 service 自由拼接
End