如何優(yōu)雅的使用 GORM 進(jìn)行分頁(yè)?
GORM 是 Go 中使用最廣泛的 ORM 包,但盡管如此,它缺少一些“基本”功能。其中一個(gè)缺失的功能就是分頁(yè)(Pagination)。
分頁(yè)是管理應(yīng)用程序中大型數(shù)據(jù)集的一個(gè)重要功能。它是一種限制和顯示數(shù)據(jù)庫(kù)中部分總數(shù)據(jù)的方法,這樣就不需要一次性檢索整個(gè)表,這樣可以極大的提高接口性能,降低超時(shí)失敗的概率。
雖然 GORM 提供了關(guān)于如何使用scopes 進(jìn)行分頁(yè)的文檔,但在靈活性和可用性方面仍有改進(jìn)的空間。在這里,我將介紹一種使用 GORM 的 Clauses 進(jìn)行分頁(yè)的替代方法。

使用 Scopes 的分頁(yè)
GORM 的官網(wǎng)文檔介紹了使用 Scopes 進(jìn)行分頁(yè)的代碼示例:
func Paginate(page, pageSize int) func(db *gorm.DB) *gorm.DB {
return func (db *gorm.DB) *gorm.DB {
// validate page and pageSize
...
offset := (page - 1) * pageSize
return db.Offset(offset).Limit(pageSize)
}
}
page := 0
pageSize := 10
db.Scopes(Paginate(page, pageSize)).Find(&users)因此,為了使用分頁(yè)功能,我們需要使用以下代碼 db.Scopes(Paginate(page, pageSize))…
使用 Clauses 的分頁(yè)
一種不同且可以說(shuō)更優(yōu)雅的方法是使用 GORM Clauses,這種方法與使用 scope 略有不同,因?yàn)?Clauses 負(fù)責(zé)修改數(shù)據(jù)庫(kù)查詢(xún),特別是 WHERE 子句。
讓我們先定義分頁(yè)結(jié)構(gòu)體:
type Pagination struct {
page int
pageSize int
}
func (p *Pagination) GetPage() int {
return p.page
}
func (p *Pagination) GetPageSize() int {
return p.pageSize
}然后,讓我們實(shí)現(xiàn)兩個(gè)接口,以便在 Gorm Clauses 函數(shù)中使用這個(gè)結(jié)構(gòu)體:
clause.Expression
gorm.StatementModifier所以結(jié)構(gòu)看起來(lái)是這樣的:
func (p *Pagination) ModifyStatement(stm *gorm.Statement) {
// We modify statement to add the pagination
db := stm.DB
stm.DB.Limit(p.size).Offset((p.page - 1) * p.pageSize)
}
func (p *Pagination) Build(_ clause.Builder) {
// The Build method is left empty since pagination does not require any additional SQL clauses.
}之后,可以按照以下方式使用分頁(yè):
pagination := Pagination{
page: 0,
pageSize: 10,
}
db.Clauses(&pagination).Find(&users)為了使這種方法可重用并增強(qiáng)其功能,這里介紹一個(gè)小眾的包 PaGorminator[4]:一個(gè)利用此功能進(jìn)行分頁(yè)的庫(kù),同時(shí)添加了其他功能,如無(wú)分頁(yè)請(qǐng)求和自動(dòng)填充元數(shù)據(jù),如總頁(yè)數(shù)和總計(jì)數(shù)。
使用方法如下:
// Add plugin
_ = db.Use(pagorminator.PaGormMinator{})
...
pageRequest, _ := pagorminator.PageRequest(0, 10)
db.Clauses(pageRequest).Find(&users)
// this will apply pagination, and also populate pageRequest with:
// - the total number of pages
// - total count






























