chore(git): 更新.gitignore以忽略新的本地文件
Some checks failed
SonarQube Analysis / sonarqube (push) Has been cancelled
Some checks failed
SonarQube Analysis / sonarqube (push) Has been cancelled
This commit is contained in:
284
.qoder/repowiki/zh/content/API参考/材质API/分页处理机制.md
Normal file
284
.qoder/repowiki/zh/content/API参考/材质API/分页处理机制.md
Normal file
@@ -0,0 +1,284 @@
|
||||
# 分页处理机制
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [texture_service_test.go](file://internal/service/texture_service_test.go)
|
||||
- [texture_service.go](file://internal/service/texture_service.go)
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go)
|
||||
- [texture_handler.go](file://internal/handler/texture_handler.go)
|
||||
- [response.go](file://internal/model/response.go)
|
||||
- [common.go](file://internal/types/common.go)
|
||||
- [routes.go](file://internal/handler/routes.go)
|
||||
- [texture.go](file://internal/model/texture.go)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构总览](#架构总览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖分析](#依赖分析)
|
||||
7. [性能考量](#性能考量)
|
||||
8. [故障排查指南](#故障排查指南)
|
||||
9. [结论](#结论)
|
||||
|
||||
## 简介
|
||||
本文件围绕材质(Texture)相关API的分页处理机制进行系统化梳理,重点基于测试用例与实现代码,阐明以下内容:
|
||||
- 分页参数的边界处理规则:page小于1时自动设为1;pageSize小于1或大于100时自动设为20。
|
||||
- repository层如何通过Offset与Limit实现分页查询,并说明Preload('Uploader')对查询性能的影响。
|
||||
- 分页响应中包含总数(total)的设计目的与客户端使用建议。
|
||||
- 分页查询的性能优化策略,包括索引使用与大数据量下的性能考虑。
|
||||
|
||||
## 项目结构
|
||||
与分页处理直接相关的模块分布如下:
|
||||
- Handler层:负责接收HTTP请求、解析分页参数、调用服务层并构造分页响应。
|
||||
- Service层:对分页参数进行边界校正,然后委托repository层执行查询。
|
||||
- Repository层:使用GORM构建查询,统计总数并按Offset/Limit分页,必要时Preload关联对象。
|
||||
- Model层:定义实体及索引,为分页查询提供索引支持。
|
||||
- Response模型:统一分页响应结构,包含total、page、per_page等字段。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "HTTP层"
|
||||
R["routes.go<br/>注册路由"]
|
||||
H["texture_handler.go<br/>处理GET /texture/*"]
|
||||
end
|
||||
subgraph "服务层"
|
||||
S["texture_service.go<br/>边界校正与调用仓库"]
|
||||
end
|
||||
subgraph "仓库层"
|
||||
REPO["texture_repository.go<br/>Offset/Limit分页与Preload"]
|
||||
end
|
||||
subgraph "模型层"
|
||||
M["texture.go<br/>实体与索引"]
|
||||
end
|
||||
subgraph "响应模型"
|
||||
RESP["response.go<br/>PaginationResponse(total/page/per_page)"]
|
||||
end
|
||||
R --> H
|
||||
H --> S
|
||||
S --> REPO
|
||||
REPO --> M
|
||||
H --> RESP
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [routes.go](file://internal/handler/routes.go#L42-L61)
|
||||
- [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|
||||
- [texture_service.go](file://internal/service/texture_service.go#L81-L103)
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L43-L112)
|
||||
- [texture.go](file://internal/model/texture.go#L16-L36)
|
||||
- [response.go](file://internal/model/response.go#L10-L18)
|
||||
|
||||
章节来源
|
||||
- [routes.go](file://internal/handler/routes.go#L42-L61)
|
||||
- [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|
||||
- [texture_service.go](file://internal/service/texture_service.go#L81-L103)
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L43-L112)
|
||||
- [texture.go](file://internal/model/texture.go#L16-L36)
|
||||
- [response.go](file://internal/model/response.go#L10-L18)
|
||||
|
||||
## 核心组件
|
||||
- 分页参数边界处理:在服务层对page与pageSize进行强制校正,确保合法范围。
|
||||
- Offset/Limit分页:仓库层使用Offset与Limit执行分页查询,并在需要时Preload关联对象。
|
||||
- 分页响应结构:统一的PaginationResponse包含total、page、per_page,便于前端计算总页数与导航。
|
||||
- 索引设计:模型层定义了多处索引,有助于提升分页查询与过滤性能。
|
||||
|
||||
章节来源
|
||||
- [texture_service.go](file://internal/service/texture_service.go#L81-L103)
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L43-L112)
|
||||
- [response.go](file://internal/model/response.go#L10-L18)
|
||||
- [texture.go](file://internal/model/texture.go#L16-L36)
|
||||
|
||||
## 架构总览
|
||||
下图展示了从HTTP请求到分页响应的关键流程,以及各层之间的职责划分。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as "客户端"
|
||||
participant G as "Gin路由(routes.go)"
|
||||
participant H as "纹理处理器(texture_handler.go)"
|
||||
participant S as "纹理服务(texture_service.go)"
|
||||
participant R as "纹理仓库(texture_repository.go)"
|
||||
participant DB as "数据库(GORM)"
|
||||
C->>G : "GET /api/v1/texture/my?page=...&page_size=..."
|
||||
G->>H : "转发到 GetUserTextures"
|
||||
H->>H : "解析page/page_size(默认1/20)"
|
||||
H->>S : "GetUserTextures(userID, page, page_size)"
|
||||
S->>S : "边界校正 : page>=1, 1<=page_size<=100"
|
||||
S->>R : "FindTexturesByUploaderID(uploaderID, page, pageSize)"
|
||||
R->>DB : "Count统计总数"
|
||||
R->>DB : "Preload('Uploader') + Order + Offset + Limit"
|
||||
DB-->>R : "结果集与总数"
|
||||
R-->>S : "[]Texture, total"
|
||||
S-->>H : "[]Texture, total"
|
||||
H->>H : "转换为TextureInfo切片"
|
||||
H-->>C : "PaginationResponse{data, total, page, per_page}"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [routes.go](file://internal/handler/routes.go#L42-L61)
|
||||
- [texture_handler.go](file://internal/handler/texture_handler.go#L473-L535)
|
||||
- [texture_service.go](file://internal/service/texture_service.go#L81-L103)
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L43-L69)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### 分页参数边界处理规则
|
||||
- page边界:当page小于1时,自动修正为1。
|
||||
- pageSize边界:当pageSize小于1或大于100时,自动修正为20。
|
||||
- 适用范围:服务层对“我的材质”、“搜索材质”、“我的收藏”三类接口均执行上述校正。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["进入服务层分页处理"]) --> CheckPage["校验 page < 1 ?"]
|
||||
CheckPage --> |是| FixPage["page = 1"]
|
||||
CheckPage --> |否| KeepPage["保持原值"]
|
||||
FixPage --> CheckSize["校验 pageSize < 1 或 > 100 ?"]
|
||||
KeepPage --> CheckSize
|
||||
CheckSize --> |是| FixSize["pageSize = 20"]
|
||||
CheckSize --> |否| KeepSize["保持原值"]
|
||||
FixSize --> End(["返回仓库层查询"])
|
||||
KeepSize --> End
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [texture_service.go](file://internal/service/texture_service.go#L81-L103)
|
||||
- [texture_service_test.go](file://internal/service/texture_service_test.go#L102-L161)
|
||||
- [texture_service_test.go](file://internal/service/texture_service_test.go#L163-L215)
|
||||
- [texture_service_test.go](file://internal/service/texture_service_test.go#L376-L428)
|
||||
|
||||
章节来源
|
||||
- [texture_service.go](file://internal/service/texture_service.go#L81-L103)
|
||||
- [texture_service_test.go](file://internal/service/texture_service_test.go#L102-L161)
|
||||
- [texture_service_test.go](file://internal/service/texture_service_test.go#L163-L215)
|
||||
- [texture_service_test.go](file://internal/service/texture_service_test.go#L376-L428)
|
||||
|
||||
### repository层的Offset与Limit实现
|
||||
- 统计总数:先以相同过滤条件执行Count,得到total。
|
||||
- 分页查询:计算offset=(page-1)*pageSize,随后使用Order排序、Offset与Limit分页,并在需要时Preload('Uploader')加载关联用户信息。
|
||||
- 查询范围控制:
|
||||
- “我的材质”:按uploader_id且status!= -1过滤。
|
||||
- “搜索材质”:按status=1过滤,可叠加public_only、type、关键词LIKE。
|
||||
- “我的收藏”:通过子查询获取收藏的texture_id,再按status=1过滤。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
QStart["开始查询"] --> BuildQuery["构建基础查询(过滤条件)"]
|
||||
BuildQuery --> CountTotal["Count统计总数(total)"]
|
||||
CountTotal --> CalcOffset["计算 offset = (page-1)*pageSize"]
|
||||
CalcOffset --> Preload["必要时 Preload('Uploader')"]
|
||||
Preload --> Order["Order 排序(如created_at DESC)"]
|
||||
Order --> ApplyLimit["Offset + Limit 分页"]
|
||||
ApplyLimit --> ExecFind["执行查询并返回结果集"]
|
||||
ExecFind --> Done["返回 []Texture, total"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L43-L69)
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L71-L112)
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L189-L221)
|
||||
|
||||
章节来源
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L43-L69)
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L71-L112)
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L189-L221)
|
||||
|
||||
### Preload('Uploader')对查询性能的影响
|
||||
- 优点:避免N+1查询问题,一次性加载每个材质的Uploader信息,减少额外查询次数。
|
||||
- 潜在代价:当分页结果较大时,会增加单次查询的数据量与网络传输开销;同时JOIN或Preload可能带来额外的内存与CPU消耗。
|
||||
- 建议:在高频分页场景中,若Uploader信息非必须,可考虑延迟加载或仅在详情页Preload;若必须显示作者信息,则可在业务上控制pageSize上限,平衡性能与体验。
|
||||
|
||||
章节来源
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L43-L69)
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L71-L112)
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L189-L221)
|
||||
|
||||
### 分页响应中的总数(total)设计目的与客户端使用建议
|
||||
- 设计目的:
|
||||
- 提供准确的总量信息,便于前端计算总页数与展示“共X条”等提示。
|
||||
- 协助客户端实现“无限滚动”或“上拉加载”的边界判断。
|
||||
- 客户端使用建议:
|
||||
- 使用 total 与 per_page 计算 total_pages:total_pages = ceil(total / per_page)。
|
||||
- 在首次加载后缓存 total,避免重复Count带来的性能损耗。
|
||||
- 若total变化频繁,可采用“乐观更新”策略:在新增/删除后局部更新列表与total,而非全量刷新。
|
||||
|
||||
章节来源
|
||||
- [response.go](file://internal/model/response.go#L10-L18)
|
||||
- [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|
||||
- [texture_handler.go](file://internal/handler/texture_handler.go#L473-L535)
|
||||
- [texture_handler.go](file://internal/handler/texture_handler.go#L537-L599)
|
||||
|
||||
### 分页查询的性能优化策略
|
||||
- 索引使用:
|
||||
- textures表的多处索引有助于过滤与排序:如uploader_id、is_public、hash、download_count、favorite_count、status等。
|
||||
- 搜索场景建议对name/description建立全文索引或使用更高效的检索方案(如向量检索),以降低LIKE模糊匹配成本。
|
||||
- 大数据量下的考虑:
|
||||
- 控制pageSize上限(服务层默认20,最大100),避免单页过大导致内存与网络压力。
|
||||
- 使用覆盖索引与选择性高的过滤条件优先,减少扫描范围。
|
||||
- 对频繁访问的列表页,可引入缓存(如Redis)存储热门查询结果与total,结合失效策略保证一致性。
|
||||
- 对Preload('Uploader'),若非必须,可延迟加载或按需加载,减少不必要的JOIN与数据传输。
|
||||
|
||||
章节来源
|
||||
- [texture.go](file://internal/model/texture.go#L16-L36)
|
||||
- [texture_service.go](file://internal/service/texture_service.go#L81-L103)
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L43-L112)
|
||||
|
||||
## 依赖分析
|
||||
- Handler层依赖Service层提供的分页接口,将HTTP参数转换为服务层输入,并构造统一的分页响应。
|
||||
- Service层依赖Repository层执行数据库查询,并在必要时进行参数边界校正。
|
||||
- Repository层依赖Model层的实体定义与索引,使用GORM执行Count、Offset/Limit与Preload。
|
||||
- Response模型提供统一的分页响应结构,便于前后端约定。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Handler["texture_handler.go"] --> Service["texture_service.go"]
|
||||
Service --> Repo["texture_repository.go"]
|
||||
Repo --> Model["texture.go"]
|
||||
Handler --> Resp["response.go"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|
||||
- [texture_service.go](file://internal/service/texture_service.go#L81-L103)
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L43-L112)
|
||||
- [texture.go](file://internal/model/texture.go#L16-L36)
|
||||
- [response.go](file://internal/model/response.go#L10-L18)
|
||||
|
||||
章节来源
|
||||
- [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|
||||
- [texture_service.go](file://internal/service/texture_service.go#L81-L103)
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L43-L112)
|
||||
- [texture.go](file://internal/model/texture.go#L16-L36)
|
||||
- [response.go](file://internal/model/response.go#L10-L18)
|
||||
|
||||
## 性能考量
|
||||
- 参数校正与分页:服务层的边界校正与仓库层的Offset/Limit组合,确保查询稳定可控。
|
||||
- Preload策略:在高频列表页中谨慎使用Preload('Uploader'),必要时采用延迟加载或缓存。
|
||||
- 索引与过滤:利用现有索引减少全表扫描;对搜索关键词建立高效索引或采用替代检索方案。
|
||||
- 缓存与限流:对热门列表页引入缓存与限流,降低数据库压力。
|
||||
- 分页上限:服务层默认pageSize为20,最大100,有助于控制单次查询负载。
|
||||
|
||||
[本节为通用性能指导,不直接分析具体文件]
|
||||
|
||||
## 故障排查指南
|
||||
- 常见问题与定位思路:
|
||||
- 分页参数异常:确认page与pageSize是否被正确校正(小于1设为1,超出范围设为默认值)。
|
||||
- total与实际条目不符:检查过滤条件是否一致(如status!= -1、public_only=true等)。
|
||||
- 查询缓慢:检查是否命中索引、是否使用了不必要的Preload、是否超大pageSize。
|
||||
- N+1查询:确认是否在循环中访问Uploader,避免多次查询。
|
||||
- 相关实现参考路径:
|
||||
- 分页参数边界处理:[texture_service.go](file://internal/service/texture_service.go#L81-L103)
|
||||
- 分页查询与总数统计:[texture_repository.go](file://internal/repository/texture_repository.go#L43-L112)
|
||||
- 分页响应结构:[response.go](file://internal/model/response.go#L10-L18)
|
||||
- HTTP层参数解析与响应构造:[texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|
||||
|
||||
章节来源
|
||||
- [texture_service.go](file://internal/service/texture_service.go#L81-L103)
|
||||
- [texture_repository.go](file://internal/repository/texture_repository.go#L43-L112)
|
||||
- [response.go](file://internal/model/response.go#L10-L18)
|
||||
- [texture_handler.go](file://internal/handler/texture_handler.go#L225-L291)
|
||||
|
||||
## 结论
|
||||
本项目的材质相关API分页处理遵循清晰的边界校正与统一响应规范。服务层负责参数合法性保障,仓库层通过Count+Offset/Limit实现高效分页,并在必要时Preload关联对象。分页响应中的total为前端提供了可靠的分页计算依据。结合现有索引与合理的pageSize上限,系统在大多数场景下能够稳定运行。针对高频列表页,建议进一步引入缓存与按需加载策略,以应对更大规模的数据与更高的并发需求。
|
||||
Reference in New Issue
Block a user