# 缓存策略实施

<cite>
**本文引用的文件**
- [README.md](file://README.md)
- [composer.json](file://composer.json)
- [composer.lock](file://composer.lock)
- [public/index.php](file://public/index.php)
- [public/api.php](file://public/api.php)
- [public/themes/admin_default/admin/setting/clear_cache.html](file://public/themes/admin_default/admin/setting/clear_cache.html)
- [public/plugins/swagger/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php](file://public/plugins/swagger/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php)
- [public/plugins/swagger/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php](file://public/plugins/swagger/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php)
- [public/static/js/artDialog/artDialog.js](file://public/static/js/artDialog/artDialog.js)
</cite>

## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)

## 引言
本指南围绕 ThinkCMF 的多层缓存策略进行系统化梳理，目标是帮助开发者在应用层、数据库查询层与分布式缓存层之间建立清晰的缓存架构，并给出缓存键设计原则、不同数据类型的缓存策略、性能优化技巧、监控与分析方法以及最佳实践与故障排查建议。由于当前仓库未直接暴露 ThinkCMF 的缓存实现代码，本指南以现有文件为依据，结合 ThinkCMF 的整体技术栈与常见实践，提供可落地的实施建议与参考路径。

## 项目结构
- 入口文件位于 public 目录，分别提供 Web 前端入口与 API 入口，二者均通过 Composer 自动加载与 ThinkPHP 运行时启动。
- 项目使用 PSR-4 自动加载，核心命名空间映射至 app、api、plugins、themes 等目录。
- 项目依赖 ThinkCMF 核心包与 API 包，这些包内部可能包含缓存相关的实现或约定。
- 后台提供了“清缓存”页面，表明系统具备缓存清理能力，但具体实现需结合核心包与配置。

```mermaid
graph TB
A["public/index.php<br/>Web 入口"] --> B["Composer 自动加载<br/>PSR-4 映射"]
C["public/api.php<br/>API 入口"] --> B
B --> D["应用命名空间<br/>app\\、api\\、plugins\\、themes\\"]
D --> E["ThinkCMF 核心包<br/>thinkcmf/cmf-app、cmf-api"]
E --> F["缓存接口/实现<br/>PSR-16/Simple Cache、PSR-6/Cache"]
```

**图表来源**
- [public/index.php](file://public/index.php)
- [public/api.php](file://public/api.php)
- [composer.json](file://composer.json)

**章节来源**
- [composer.json:46-56](file://composer.json#L46-L56)
- [README.md:96-101](file://README.md#L96-L101)

## 核心组件
- 入口与自动加载：Web 与 API 入口负责初始化运行时与自动加载，后续的缓存策略应在应用启动阶段完成初始化与配置。
- 缓存接口与实现：
  - PSR-16 简单缓存接口已在项目依赖中体现，可用于应用层缓存。
  - PSR-6 缓存池接口亦在依赖中出现，适合分布式缓存场景。
  - Doctrine Annotations 提供了基于 PSR-6 的注解缓存读取器，可作为注解元数据缓存的参考实现。
- 清理与运维：后台提供“清缓存”页面，便于集中清理系统缓存，应与应用层缓存策略配合使用。

**章节来源**
- [composer.lock:471-512](file://composer.lock#L471-L512)
- [public/plugins/swagger/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php:19-56](file://public/plugins/swagger/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php#L19-L56)
- [public/themes/admin_default/admin/setting/clear_cache.html:1-42](file://public/themes/admin_default/admin/setting/clear_cache.html#L1-L42)

## 架构总览
ThinkCMF 的缓存架构可按“三层”设计：
- 应用层缓存：面向进程内或本地缓存，如内存缓存、文件缓存等，适合高频读取且体量较小的数据。
- 数据库查询缓存：对查询结果进行缓存，减少数据库压力；可与 ORM 层集成，实现查询级缓存。
- 分布式缓存：面向多实例、高并发场景，使用 Redis/Memcached 等，提供统一缓存池与失效策略。

```mermaid
graph TB
subgraph "应用层"
AL["应用层缓存<br/>PSR-16 简单缓存"]
end
subgraph "数据库层"
QL["查询缓存<br/>ORM 查询结果缓存"]
end
subgraph "分布式层"
DL["分布式缓存<br/>Redis/Memcached<br/>PSR-6 缓存池"]
end
AL --> QL
QL --> DL
```

[本图为概念性架构示意，无需图表来源]

## 详细组件分析

### 组件一：应用层缓存（PSR-16）
- 设计要点
  - 使用 PSR-16 接口统一缓存操作，确保在不同后端间切换时保持一致的调用方式。
  - 对热点数据采用短 TTL 并结合“延迟双删”或“先更新后失效”的策略，降低不一致风险。
  - 对列表数据采用“分页键 + 子键”的组合命名，避免全量重建。
- 实施建议
  - 在应用启动阶段初始化缓存客户端，注入到服务层或中间件。
  - 对写操作采用“先写数据库，再写缓存”的顺序，失败回滚时同步回滚缓存。
  - 对读操作采用“先读缓存，后读数据库”的顺序，命中率低时回源并写入缓存。

```mermaid
flowchart TD
Start(["开始"]) --> ReadCache["读取缓存"]
ReadCache --> Hit{"命中？"}
Hit --> |是| ReturnCache["返回缓存数据"]
Hit --> |否| ReadDB["读取数据库"]
ReadDB --> DBOK{"读取成功？"}
DBOK --> |否| ReturnErr["返回错误"]
DBOK --> |是| WriteCache["写入缓存"]
WriteCache --> ReturnDB["返回数据库数据"]
ReturnCache --> End(["结束"])
ReturnDB --> End
ReturnErr --> End
```

[本图为通用流程示意，无需图表来源]

**章节来源**
- [composer.lock:471-512](file://composer.lock#L471-L512)

### 组件二：数据库查询缓存
- 设计要点
  - 将查询结果以 SQL 或查询参数为键进行缓存，避免重复执行相同查询。
  - 对动态条件查询，建议采用“参数哈希 + SQL 片段”生成稳定键名。
  - 结合 ORM 的生命周期钩子，在写操作时主动失效相关查询缓存。
- 实施建议
  - 在模型或仓储层封装查询缓存逻辑，对外提供统一的查询接口。
  - 对复杂查询（含 JOIN、聚合）采用“主键集合 + 单条详情缓存”的二级缓存策略。

```mermaid
sequenceDiagram
participant C as "调用方"
participant S as "服务层"
participant Q as "查询缓存"
participant DB as "数据库"
C->>S : 发起查询请求
S->>Q : 获取查询结果缓存
alt 命中
Q-->>S : 返回缓存结果
S-->>C : 返回结果
else 未命中
S->>DB : 执行查询
DB-->>S : 返回查询结果
S->>Q : 写入查询缓存
S-->>C : 返回结果
end
```

[本图为通用序列示意，无需图表来源]

**章节来源**
- [README.md:209-223](file://README.md#L209-L223)

### 组件三：分布式缓存（PSR-6）
- 设计要点
  - 使用 PSR-6 缓存池接口对接 Redis/Memcached，实现跨实例共享缓存。
  - 为不同业务模块划分命名空间前缀，避免键冲突。
  - 对高并发场景设置合理的过期时间与重试策略，防止缓存击穿。
- 实施建议
  - 在服务层注入缓存池客户端，对热点数据设置短 TTL 并开启“互斥锁”防雪崩。
  - 对列表数据采用“分片键 + 子键”，提升并发下的缓存命中率。

```mermaid
classDiagram
class CachePoolInterface {
+get(key) mixed
+set(key, value, ttl) bool
+delete(key) bool
+has(key) bool
}
class RedisCachePool {
+connect()
+get(key) mixed
+set(key, value, ttl) bool
+delete(key) bool
+has(key) bool
}
CachePoolInterface <|.. RedisCachePool
```

[本图为概念性类图，无需图表来源]

**章节来源**
- [composer.lock:471-512](file://composer.lock#L471-L512)

### 组件四：注解缓存（Doctrine Annotations）
- 设计要点
  - 注解读取器支持基于 PSR-6 的缓存读取，可显著降低注解扫描成本。
  - 通过缓存键存储注解元数据，避免重复解析。
- 实施建议
  - 在生产环境启用注解缓存，开发环境可关闭以获得更快的迭代反馈。
  - 对注解变更频繁的模块，提供缓存清理入口。

```mermaid
sequenceDiagram
participant R as "AnnotationReader"
participant P as "PsrCachedReader"
participant C as "CacheItemPoolInterface"
R->>P : 请求注解元数据
P->>C : 读取缓存
alt 命中
C-->>P : 返回缓存项
P-->>R : 返回注解元数据
else 未命中
P->>R : 解析注解
R-->>P : 返回注解元数据
P->>C : 写入缓存
P-->>R : 返回注解元数据
end
```

**图表来源**
- [public/plugins/swagger/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php:19-56](file://public/plugins/swagger/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php#L19-L56)

**章节来源**
- [public/plugins/swagger/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php:19-56](file://public/plugins/swagger/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php#L19-L56)
- [public/plugins/swagger/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php:86-113](file://public/plugins/swagger/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php#L86-L113)

### 组件五：前端缓存与清理（artDialog 与后台清缓存页面）
- 设计要点
  - 前端库提供元素级数据缓存能力，可用于临时状态保存与交互体验优化。
  - 后台提供“清缓存”页面，便于运维人员一键清理系统缓存。
- 实施建议
  - 在前端交互中谨慎使用元素级缓存，避免持久化敏感数据。
  - 在系统升级或配置变更后，通过后台清缓存页面触发缓存清理。

```mermaid
flowchart TD
A["用户点击清缓存"] --> B["后台触发清理流程"]
B --> C["删除应用层缓存"]
B --> D["删除分布式缓存"]
B --> E["刷新页面"]
C --> F["完成"]
D --> F
E --> F
```

**图表来源**
- [public/themes/admin_default/admin/setting/clear_cache.html:1-42](file://public/themes/admin_default/admin/setting/clear_cache.html#L1-L42)

**章节来源**
- [public/static/js/artDialog/artDialog.js:301-348](file://public/static/js/artDialog/artDialog.js#L301-L348)
- [public/themes/admin_default/admin/setting/clear_cache.html:1-42](file://public/themes/admin_default/admin/setting/clear_cache.html#L1-L42)

## 依赖分析
- 自动加载与命名空间
  - 项目通过 PSR-4 将 app、api、plugins、themes 映射到对应目录，便于在各层实现缓存策略。
- 缓存接口依赖
  - 项目依赖 PSR-16 与 PSR-6，为应用层与分布式缓存提供统一抽象。
- 注解缓存依赖
  - Doctrine Annotations 提供基于 PSR-6 的注解缓存读取器，有助于降低注解解析成本。

```mermaid
graph LR
A["PSR-16 简单缓存"] --> B["应用层缓存"]
C["PSR-6 缓存池"] --> D["分布式缓存"]
E["Doctrine Annotations<br/>PsrCachedReader"] --> D
B --> D
```

**图表来源**
- [composer.lock:471-512](file://composer.lock#L471-L512)
- [public/plugins/swagger/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php:19-56](file://public/plugins/swagger/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php#L19-L56)

**章节来源**
- [composer.json:46-56](file://composer.json#L46-L56)
- [composer.lock:471-512](file://composer.lock#L471-L512)

## 性能考虑
- 缓存预热
  - 在系统启动或低峰期预热热点数据，减少上线初期的缓存冷启动。
- 缓存雪崩预防
  - 对高价值缓存设置随机 TTL，避免同时过期；对热点键加互斥锁，仅允许一个请求回源。
- 缓存一致性
  - 写操作采用“先写数据库，再写缓存”的顺序；对批量更新采用失效策略而非逐条写入。
- 缓存穿透防护
  - 对空结果也进行短 TTL 缓存，避免恶意请求持续打穿；对非法参数进行校验与限流。
- 列表与详情缓存
  - 列表采用“分页键 + 子键”策略；详情采用“主键 + 版本号”策略，避免脏读。

[本节为通用性能建议，无需章节来源]

## 故障排查指南
- 清理缓存
  - 通过后台“清缓存”页面触发系统缓存清理，适用于配置变更或升级后的缓存不一致问题。
- 注解缓存异常
  - 若注解读取异常，检查注解缓存是否启用，必要时清理注解缓存并重启服务。
- 前端交互缓存
  - 若前端交互状态异常，检查元素级缓存是否被误用或未正确清理。

**章节来源**
- [public/themes/admin_default/admin/setting/clear_cache.html:1-42](file://public/themes/admin_default/admin/setting/clear_cache.html#L1-L42)
- [public/static/js/artDialog/artDialog.js:301-348](file://public/static/js/artDialog/artDialog.js#L301-L348)

## 结论
ThinkCMF 已在依赖层面提供了 PSR-16/PSR-6 缓存接口与注解缓存能力，结合入口文件与自动加载机制，可在应用层、数据库查询层与分布式缓存层构建完整的多层缓存体系。建议在实际项目中遵循缓存键命名规范、失效策略与一致性保障原则，并结合预热、雪崩预防与穿透防护等手段，持续优化缓存性能与稳定性。

## 附录
- 参考路径
  - 入口文件：[public/index.php](file://public/index.php)，[public/api.php](file://public/api.php)
  - 自动加载与命名空间：[composer.json:46-56](file://composer.json#L46-L56)
  - 缓存接口依赖：[composer.lock:471-512](file://composer.lock#L471-L512)
  - 注解缓存实现：[PsrCachedReader.php:19-56](file://public/plugins/swagger/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php#L19-L56)
  - 清理缓存页面：[clear_cache.html:1-42](file://public/themes/admin_default/admin/setting/clear_cache.html#L1-L42)