应使用c.query("page")和c.query("size")获取分页参数并手动解析,设默认值且限制size≤100;sql推荐游标分页(where id
分页参数怎么从请求里安全取出来
直接用
c.Param("page")或c.Query("page")是错的——Iris 的 MVC 不自动绑定查询参数到 controller 方法参数,得手动解析。常见错误是没校验类型和范围,导致strconv.Atoipanic 或传入负数、0 造成 SQL LIMIT 负值。
- 统一用
c.Query("page")和c.Query("size")拿字符串,避免路径参数污染- 用
strconv.ParseInt转整型,并设默认值(如 page=1, size=20)- 强制限制
size上限(比如 ≤100),防止恶意拉取全表- 注意:Iris 的
Query返回空字符串时,ParseInt会报错,必须先判空SQL 查询怎么写才不跳数据或重复
Iris 本身不处理分页逻辑,最终靠数据库 OFFSET/LIMIT 或游标实现。OFFSET 方式简单但深度分页性能差;游标适合高并发场景但需唯一有序字段(如
id或created_at)。
- OFFSET 写法:
SELECT * FROM users ORDER BY id DESC LIMIT ? OFFSET ?,其中OFFSET = (page-1) * size- 游标写法(推荐):
SELECT * FROM users WHERE id ,上一页最后一条的 <code>id作为下一页的 cursor- 别在 ORDER BY 里用非索引字段(如
name),否则 MySQL 可能全表扫描- 如果用 GORM,注意
Limit().Offset()会拼出 OFFSET,而Where("id 才是游标怎么把分页结果塞进 Iris 的 MVC 返回结构里
Iris MVC 的 controller 方法返回值会被自动序列化为 JSON,但分页需要额外元信息(总条数、当前页、总页数等),不能只返数据切片。
- 定义结构体,比如:
type PageResult struct { Data interface{} `json:"data"` Total int64 `json:"total"` Page int `json:"page"` Size int `json:"size"` TotalPages int `json:"total_pages"` }- 查总数别用
SELECT COUNT(*)加子查询套整个 SELECT —— 先单独查一次COUNT,再查数据,更可控- 不要在 controller 里拼 SQL 字符串,用参数化查询防注入;Iris 的
c.ServeJSON会自动设 Content-Type,不用手动写c.Header- 如果用自定义响应封装(如
Success(c, data)),确保PageResult字段名和前端约定一致,避免驼峰/下划线混乱为什么分页接口总在第 100 页之后变慢
这不是 Iris 的问题,而是 OFFSET 越大,MySQL 越要扫描前面所有行。实测 10 万数据、OFFSET 10000 时,响应可能从 20ms 涨到 800ms。
- 上线前必须压测真实数据量下的分页性能,别只用 100 条测试
- 加复合索引:比如按
status, created_at DESC分页,索引就得是(status, created_at)- 对管理后台类接口,可限制最大页码(如
if page > 1000 { page = 1000 }),比硬扛更实际- 游标分页无法跳转任意页,但支持“下一页”“上一页”足够多数场景;真要跳页,前端应改用搜索+筛选替代
分页看着简单,但 offset 性能陷阱、总数一致性、游标边界条件(比如新数据插入导致漏掉记录)这些点,线上最容易出问题。别等用户投诉了才查慢查询日志。












