生产环境踩到的问题:升级中途若短暂运行过旧版二进制,AutoMigrate 会把 attachments 表从 id=1 重新创建,新上传的行获得 1、2、3……与 files 表已迁移行的 id 撞号。原迁移按 id 对齐的 NOT EXISTS 会把这些行误判为“已迁移”,新上传数据被静默漏搬(files 表缺失记录,文章附件列表为空)。
修复
migrateAttachmentsToFiles 在 id 对齐迁移之后,追加一段按内容回退:
-- id 已存在但指向不同内容(重建表后撞号)的行,省略 id 由数据库重新分配;
-- 内容(stored_name,SHA-256)已在 files 中登记的行跳过(去重)
INSERTINTOfiles(type,…)SELECT'attachments',…FROMattachmentsaWHEREEXISTS(SELECT1FROMfilesfWHEREf.id=a.idANDf.stored_name<>a.stored_name)ANDNOTEXISTS(SELECT1FROMfilesfWHEREf.stored_name=a.stored_name);
## 背景
生产环境踩到的问题:升级中途若短暂运行过旧版二进制,AutoMigrate 会把 `attachments` 表从 id=1 重新创建,新上传的行获得 1、2、3……与 files 表已迁移行的 id 撞号。原迁移按 id 对齐的 `NOT EXISTS` 会把这些行误判为“已迁移”,**新上传数据被静默漏搬**(files 表缺失记录,文章附件列表为空)。
## 修复
`migrateAttachmentsToFiles` 在 id 对齐迁移之后,追加一段**按内容回退**:
```sql
-- id 已存在但指向不同内容(重建表后撞号)的行,省略 id 由数据库重新分配;
-- 内容(stored_name,SHA-256)已在 files 中登记的行跳过(去重)
INSERT INTO files (type, …)
SELECT 'attachments', …
FROM attachments a
WHERE EXISTS (
SELECT 1 FROM files f WHERE f.id = a.id AND f.stored_name <> a.stored_name
)
AND NOT EXISTS (
SELECT 1 FROM files f WHERE f.stored_name = a.stored_name
);
```
仍保持幂等(重复启动不产生重复数据),仅在旧表仍存在时执行。
## 验证
本机线上库已按该策略手工恢复 3 条漏搬记录(文章 10/11/12 的真实上传,磁盘文件完整);`go build` + 全量测试通过。
场景:中途部署过旧版二进制时 AutoMigrate 会把 attachments 以
id=1 重新编号;此前按 id 对齐的 NOT EXISTS 会误判已迁移,
导致新上传行静默丢失。现在第二段按 stored_name(内容 SHA-256)
补齐 id 冲突的行(省略 id 由数据库重新分配,内容已登记则跳过)。
kevin
merged commit a6c1f92197 into main2026-08-28 20:04:57 +08:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
背景
生产环境踩到的问题:升级中途若短暂运行过旧版二进制,AutoMigrate 会把
attachments表从 id=1 重新创建,新上传的行获得 1、2、3……与 files 表已迁移行的 id 撞号。原迁移按 id 对齐的NOT EXISTS会把这些行误判为“已迁移”,新上传数据被静默漏搬(files 表缺失记录,文章附件列表为空)。修复
migrateAttachmentsToFiles在 id 对齐迁移之后,追加一段按内容回退:仍保持幂等(重复启动不产生重复数据),仅在旧表仍存在时执行。
验证
本机线上库已按该策略手工恢复 3 条漏搬记录(文章 10/11/12 的真实上传,磁盘文件完整);
go build+ 全量测试通过。