Beego分页需手动组合Limit()和Offset()并正确计算Offset=(page-1)*pageSize;Count()必须复用相同Filter条件;v2+的paginator包仅辅助生成页码,不执行SQL;深度分页应改用游标分页提升性能。

Beego 中用 QueryTable().Limit().Offset() 做分页最直接
Beego 的 ORM(orm 包)本身不提供封装好的「分页方法」,但通过组合 Limit() 和 Offset() 就能准确实现。关键不是找现成函数,而是算对偏移量:Offset = (page - 1) * pageSize。
常见错误是把 page 当成从 0 开始——Beego 分页习惯按前端传的「第 1 页、第 2 页」处理,所以必须减 1。
- 假设当前页码
page = 3,每页 10 条 →Offset(20).Limit(10) - 查询总数必须单独执行
Count(),不能靠Len(),因为Len()只返回本次查出的条数 - 别在
QueryTable().Filter().Limit().Offset()链式调用里漏掉Filter()条件——条件写错位置会导致分页结果错乱
分页时 Count() 必须和主查询条件完全一致
很多人分页后总条数对不上,根本原因是 Count() 没复用同样的 Filter() 和 Exclude() 条件。ORM 不会自动帮你同步条件,得手动写两遍或提取成变量。
例如要查 status=1 且 name 包含 "test" 的记录:
qs := o.QueryTable(&User{}).Filter("status", 1).Filter("name__icontains", "test")
total, _ := qs.Count() // ✅ 条件一致
users := make([]User, 0)
qs.Limit(pageSize).Offset(offset).All(&users) // ✅ 复用 qs如果 Count() 是另起一行写 o.QueryTable(&User{}).Count(),那就只统计了全表,和分页结果无关。
Beego v2+ 的 paginator 包只是辅助计算,不参与数据库操作
Beego 2.x 引入了 github.com/beego/beego/v2/server/web/paginator,但它只负责生成页码 HTML 或计算上一页/下一页链接,**不执行 SQL,也不调 ORM**。它需要你提前把总数、当前页、每页条数传进去。
- 它不替代
Limit()/Offset(),只是帮你省去手动算HasNext/HasPrev的逻辑 - 如果你用模板渲染分页栏,
paginator的GetPages()返回的是页码数组,不是数据 - 注意:v1 用户别直接 import 这个包——v1 没这个路径,得升级或手写分页逻辑
性能敏感场景避免 OFFSET 深度分页
当 page 很大(比如第 10000 页),OFFSET 99990 会让数据库扫过前 99990 行再取结果,MySQL/PostgreSQL 都会明显变慢。
- 真实项目建议改用「游标分页」:用上一页最后一条记录的
id或时间戳做条件,如WHERE id > ? ORDER BY id LIMIT 10 - Beego ORM 支持这种写法:
qs.Filter("id__gt", lastID).Limit(10) - 如果必须用页码分页,至少给
ORDER BY字段加索引,否则OFFSET会更慢
分页看似简单,但总数一致性、深度偏移、ORM 条件复用这三点,漏掉任何一个都会让列表翻页出 bug。


















