分页必须用 limit 和 offset,gorm 无原生 paginate;offset 表示跳过条数,须在 limit 前调用;必须显式 order 排序;前端参数需校验并截断;总数查询应独立执行且避免复用链式 db 实例。

分页必须用 Limit 和 Offset,别信“自动分页”封装
GORM 本身不提供 Paginate 这类开箱即用的分页方法(v2 仍无原生支持),所谓“自动分页”基本是第三方库或自己写的封装。直接用 Limit 和 Offset 最可控、最透明,也最不容易出错。
-
Limit(n)控制每页取多少条,必须显式传整数,传 0 或负数会导致查出全表或 panic -
Offset(m)表示跳过前 m 条——注意不是“第 m 页”,而是“从第 m+1 条开始取”,所以第 2 页(每页 10 条)要Offset(10),不是Offset(2) - 顺序很重要:
Offset必须在Limit前调用才生效(GORM v2 中二者顺序可互换,但为兼容性和可读性,建议固定为Offset().Limit()) - 没加
Order的分页结果不稳定:数据库不保证无序查询的行序,同一页可能漏数据或重复,必须显式指定排序字段(如Order("id ASC"))
前端传 page 和 page_size,后端得做安全校验
前端 URL 常见形如 /users?page=3&page_size=20,但不能直接拿过来算 Offset。用户可能传负数、超大数、非数字,或者 page_size 设成 10000 导致慢查询甚至 DB 拒绝服务。
- 用
c.ShouldBindQuery(&p)绑定结构体比手动c.Query()更安全,能统一做字段验证 -
PageNum小于等于 0 时强制设为 1;PageSize超过上限(比如 100)就截断,避免被恶意刷 - 别把
page_size直接透传给Limit,先和配置里的最大值取min,例如limit := min(p.PageSize, config.MaxPageSize) - 如果用户传了非法参数(如
page=abc),ShouldBindQuery会返回 error,此时应直接c.JSON(400, ...),别默默 fallback
总数查询不能省,但别和列表查写在一个事务里
前端分页控件需要总条数来算页码数,所以几乎每次分页都要查一次 COUNT(*)。但它和主查询是两个独立 SQL,不该共用同一个 *gorm.DB 实例链式调用(否则 Where 条件会污染)。
- 正确做法:先构建带条件的
db实例(比如加了Where("status = ?", "active")),再分别调用Count(&count)和Limit().Offset().Find() - 错误写法:
db.Where(...).Count().Limit().Offset().Find()—— GORM v2 中Count会清空Limit/Offset,但条件仍保留;不过语义混乱,易维护错 - 性能提示:如果表很大且总数变化不频繁,可以考虑缓存总数(比如 Redis 存 5 分钟),但首次加载或带搜索条件时仍要实时查
- 别用
Find(&list).RowsAffected取总数——它返回的是本次Find查到的条数(即page_size),不是全量总数
多条件筛选 + 分页,用链式 Where 构建动态查询
真实接口往往要支持 name 模糊、status 等值、time_range 范围等组合筛选,这些条件不是每次都存在,得动态拼。
- 核心原则:从基础
db开始,用中间变量逐步叠加Where,不要直接改全局DB实例 - 例如:
query := DB.Model(&User{}),再根据参数决定是否query = query.Where("name LIKE ?", "%"+name+"%") - 字符串模糊匹配记得用
LIKE而不是=;时间范围用BETWEEN或两个Where(Where("created_at >= ?", start).Where("created_at ) - 排序字段也要支持动态:
if p.Desc { query = query.Order("updated_at DESC") } else { query = query.Order("updated_at ASC") } - 如果条件太多,可考虑用
Scopes抽成函数复用,比如ActiveOnly、ByDeptID,但注意它们只是语法糖,不影响分页逻辑本身
Order 导致数据错乱、page_size 缺少上限被拖垮 DB、总数查询和列表查询条件不一致导致页码跳变。这些都不是框架问题,是写法细节没抠准。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











