图片不再随数据集删除:加「图片挂载恢复」,place_images 摘掉外键
用户报「之前上传的照片找不到了,应该是因为清了应用数据换基线」。查下来与 App 侧无关, 是站点自己两套口径打架: - place_images.dataset_id 带 ON DELETE CASCADE,而读取按 place_key 坐标键、跨数据集。 - 于是删掉旧数据集时图片**行**被级联删了,**文件却留在 media 目录里**。 - 实测(本机):datasets 只剩 155 号、place_images 0 行、盘上 4 个 .webp 好端端躺着。 同一批附属数据里备注(17)与结论(3+1)因为早就迁到坐标键,毫发无损——只有图片倒霉。 三件事: 1) 恢复:后台首页「图片挂载恢复 → 扫描并恢复」(POST /admin/images/recover, internal/web/image_recovery.go)。只插行、不删文件、不看数据集,按 object_key 判重可反复点。 认地点两处来源:数据集还在就查它的 places;数据集已删就读它留下的 baselines/<id>.sqlite 还原「地点号 → 坐标」。对象键两种历史布局都认(<ds>/<YYYYMM>/<srcPK>-<hash>.webp 与 <ds>/<srcPK>/<hash>.webp);判据先看文件名有没有 `<数字>-` 前缀,再看中间目录—— 地点号也可能刚好 6 位,只看位数会认错。 2) 防复发:CREATE TABLE place_images 去掉外键 + 幂等 DROP CONSTRAINT;删图接口不再按 dataset_id 过滤(数据集删了也得能删图);「删除数据集」的二次确认文案改成实话。 3) 报告同类陷阱(未改):topics 仍带 CASCADE,专题随数据集一起删且没有恢复来源。 测试踩到的坑:图片「按坐标键跨数据集读」+「按 object_key 判重」都不看数据集,用例之间会 互相污染两处——盘上文件(报「应当 2 张、实际 10 张」)与库里的行(Already:1 让兜底分支 根本没跑到,用例差点假绿)。加 isolateImageState(换空 DataDir + 按 place_key 清历史行), 并给夹具补收尾清理(外键没了必须自己清)。 新增用例 4 条;验收:./scripts/verify.sh 全量 PASS=323 FAIL=0 SKIP=0。
This commit is contained in:
@@ -211,3 +211,33 @@ UUID 集合也与换之前逐条一致)。
|
||||
|
||||
第二轮全量验收:**PASS=319 FAIL=0 SKIP=0**。技能 `rond-backup-parse` 补了「导出条数 ≠ 站点条数」
|
||||
与「换基线已做成后台动作」两处。
|
||||
|
||||
## 图片丢失的根因与恢复(2026-09-30 19:40)
|
||||
|
||||
用户报「之前上传的照片现在找不到了,应该是因为清了应用数据换基线」。查下来**跟 App 侧无关**,
|
||||
是站点自己的外键口径不一致:
|
||||
|
||||
- `place_images.dataset_id` 带 `ON DELETE CASCADE`,而**读取按 `place_key` 坐标键、跨数据集**。
|
||||
- 于是「删掉旧数据集」把图片**行**级联删了,**文件却留在 `<data_dir>/media/<数据集>/…`**。
|
||||
- 本机实测:`datasets` 只剩 155 号,`place_images` **0 行**,盘上 4 个 `.webp` 好端端躺着。
|
||||
同一批附属数据里备注(17)与结论(3+1)因为早就迁到坐标键,**毫发无损**——只有图片倒霉。
|
||||
|
||||
做的三件事:
|
||||
1. **恢复**:`internal/web/image_recovery.go` + 后台首页「图片挂载恢复 → 扫描并恢复」(`POST /admin/images/recover`)。
|
||||
只插行、不动文件、可反复点(按 `object_key` 判重,`apply=false` 是预演)。认地点两处来源:
|
||||
① 数据集还在就查它的 `places`;② 数据集已删就读它留下的 `baselines/<id>.sqlite` 还原「地点号 → 坐标」。
|
||||
对象键两种历史布局都认(`<ds>/<YYYYMM>/<srcPK>-<hash>.webp` 与 `<ds>/<srcPK>/<hash>.webp`)。
|
||||
2. **防复发**:schema 里 `CREATE TABLE place_images` 去掉外键 + 幂等 `DROP CONSTRAINT`;
|
||||
删图的接口不再按 `dataset_id` 过滤;后台「删除数据集」的确认文案改成实话(专题也会删、附属数据不受影响)。
|
||||
3. **同类陷阱报告**:`topics` 仍带 CASCADE —— 专题随数据集一起删且**没有恢复来源**(本机 0 行,
|
||||
之前那次换数据集就没了)。专题内容本来是「时间+区域」派生的,可以做成跨数据集的,但列表/详情都按
|
||||
`dataset_id` 过滤,要改就一起改 —— **等用户拍板**,没擅自动。
|
||||
|
||||
本机预期可恢复 4 张:`上班` ×1(旧地点号 286)、`海之尚酒店` ×3(旧地点号 309),靠 `baselines/9.sqlite` 认。
|
||||
|
||||
踩到的测试坑(都写进 details 卅四):图片「按坐标键跨数据集读」+「按 object_key 判重」都**不看数据集**,
|
||||
用例之间会互相污染两处——盘上文件(「应当 2 张、实际 10 张」)与库里的行
|
||||
(`Already:1` 让兜底分支根本没跑到,用例差点假绿)。加了 `isolateImageState`(换空 DataDir + 按 place_key 清行),
|
||||
并给夹具补了收尾清理(外键没了,必须自己清)。
|
||||
|
||||
新增用例 4 条(`image_recovery_test.go`)。
|
||||
|
||||
Reference in New Issue
Block a user