# 功能测试报告_导出缓存改用数据指纹_2026-09-22 ## 一、功能说明 用户诉求:下载过一次、期间没有新导入数据就应直接沿用上次结果(已实现落盘缓存);随后用户认可「按我说的做」,要求继续解决缓存守卫的两个问题: 1. **误失效**:原来用全局 `MAX(import_batch.id)` 当版本号,导入投资/能耗这类与汇总大表无关的数据也会让缓存失效,白等十几秒; 2. **漏失效(正确性漏洞)**:版本号只反映数据库导入记录,**不含母版文件**——换母版/改参照件时版本号不变,会把旧结果当新表发出。 **改动**: | # | 改动 | 说明 | | --- | --- | --- | | 1 | 用**数据指纹**替代全局版本 | 指纹 = 「依赖源表的内容校验和」+「母版等文件身份」,SHA-256 取前 8 字节(16 位十六进制),写进缓存文件名 | | 2 | 源表范围=**排除法** | 库内所有基表,**排除**投资(3)/能耗(2)/审核(4)/系统(6)/`import_batch`(1) 共 16 张;其余一律纳入(宁可多算不可出错) | | 3 | 用 `CHECKSUM TABLE` 取校验和 | 能捕捉**原地 UPDATE**(行数、max(id) 都不变的情况),比 `count+max(id)` 更严格 | | 4 | 文件身份 | 母版目录下全部文件(母版 / 参照件 / `_备份_` 回填件)+《网约车订单及全省总量.xlsx》,取「名称+大小+修改时间」 | | 5 | 新增**失效提示**(第 3 步的提示版) | 没命中且存在旧结果时,进度弹窗显示「上次生成的结果已因数据或母版变化失效,本次按最新数据重算。」 | > 提示放在**导出时的进度弹窗**(而不是导入结果弹窗):① 正好出现在用户等待的时候;② 免去「每次导入都跑一遍全表校验和」的开销。 ## 二、测试环境 - 后端 Spring Boot 8090(重启加载新代码);前端 8080;MySQL 3308 / `traffic_audit` - 报表期 2026-08(月报);缓存目录 `docs/生成汇总大表/_cache/` - 验证期间另一个会话重启过后端两次,个别步骤中断后重跑(不影响结论) ## 三、用例表 | # | 用例 | 操作 | 预期 | 实际 | 结论 | | --- | --- | --- | --- | --- | --- | | T01 | 首次生成(新指纹) | 提交导出 | 真算并落盘,旧版本文件被清理 | `DONE` 21 s;生成 `…_v227060ce99767ced.xlsx`,原 `…_v541.xlsx` 已删 | 通过 | | T02 | 再次提交 | 同上报 | 内存命中 | **241 ms**,`fromCache=true` | 通过 | | T03 | **无关导入不影响缓存(核心)** | 往 `investment_project`、`import_batch` 各插 1 行后提交 | 仍命中 | `fromCache=true`(改造前必然失效) | 通过 | | T04 | 删除上述两行后提交 | 同上 | 仍命中 | `fromCache=true` | 通过 | | T05 | **相关源表原地 UPDATE** | `wyc_order_monthly.pin_k +0.001`(行数/`max(id)` 不变)后提交 | 必须失效 | `fromCache=false`、`RUNNING`;缓存文件名换成新指纹 `…_v68b6bc0c…` | 通过 | | T06 | 还原该值后提交 | 同上 | 仍不命中(缓存是改后指纹) | `fromCache=false` → 重算;指纹回到 `227060ce99767ced` | 通过 | | T07 | **换母版必须失效(原漏洞)** | 改母版文件修改时间(内容不变)后提交 | 必须失效 | `fromCache=false`、`RUNNING`;指纹变 `…_v7d65cbb6…` | 通过 | | T08 | 恢复母版时间后提交 | 同上 | 失效→重算→再提交命中 | 重算后 `fromCache=true` | 通过 | | T09 | 失效提示(接口) | 存在旧结果且指纹不符时提交 | `staleCache=true` | `status=RUNNING fromCache=false staleCache=true` | 通过 | | T10 | 命中缓存无提示(回归修复) | 命中时提交 | `staleCache=false` | 修复前命中仍带 `staleCache=true` → 已修为命中即清零 | 通过 | | T11 | **浏览器实测提示行** | admin/123456 → 报表生成 → 汇总大表 → 2026-08 → 导出(先改母版 mtime 制造失效) | 弹窗出现失效提示 | 弹窗显示「上次生成的结果已因数据或母版变化失效,本次按最新数据重算。」;生成 13.2 s、自动下载 1.15 MB、按钮「重新生成/关闭」、控制台 0 报错 | 通过 | | T12 | 数据还原核对 | 查库 | 无测试残留 | `import_batch` 419、`investment_project` 152、`wyc_order_monthly.2025-12 pin_k=3492.63`、无「_指纹测试项目」 | 通过 | ## 四、发现的问题与处置 | # | 问题 | 处置 | | --- | --- | --- | | P1 | 命中缓存时残留上一次的「已失效」提示标记 | 已修:命中分支清零 `staleCache` | | P2 | 文件身份用毫秒级 mtime:把母版 mtime「恢复成同一秒」时,亚秒差异仍会产生新指纹(验证中实际遇到) | 属**预期行为**(保守优先:宁可多算一次)。若将来觉得太敏感,可改为「秒级 mtime」或对母版做内容哈希 | | P3 | 测试用的临时数据(1 个投资项目、1 条导入记录、`wyc pin ±0.001`) | 已全部还原/删除,T12 已核对 | | P4 | 数据指纹计算成本 | 约 11 张表 CHECKSUM + 13 个文件 stat,实测可为毫秒级(3 张表 48 ms);仅在提交导出时算一次 | ## 五、结论 - 缓存守卫从「全局导入版本」升级为「**数据指纹**」后:**无关导入不再让缓存失效**(T03/T04),**换母版、改源表(含原地 UPDATE)必定失效**(T05/T07),两个方向都实测通过; - 生成一次的成本只花在真正需要重算的时候;正常「下载过再看一次」仍是毫秒级命中; - 失效时会在进度弹窗明确说明原因,用户不会误以为缓存坏了; - 测试数据已全部还原,库内状态与验证前一致。 测试人:Codex(AI) 测试日期:2026-09-22