有沒有過這樣的經驗?你在方格子的後台編輯文章,明明只發表過一次,卻突然發現同一篇文章「重複出現兩次」。第一反應當然是以為自己搞錯,把其中一篇刪掉、重新寫一次。結果怪事又發生了:文章不是消失、就是再度出現,完全搞不清楚到底是系統問題,還是自己眼花。
別急,這其實不是你一個人的錯,也不是「靈異事件」,而是程式設計中相當常見的「資料唯一性」問題。
一個真實的故事:0.3 元的差距
在說明之前,先講一個曾經發生過的案例。某家公司導入新的 ERP 系統,運作半年後一切看似順利:財報、損益表、資產負債表都能正確產出,數字也能勾稽。唯獨在「庫存報表」這一關,總金額和財務部門的數字總是對不起來。差距不大,有時候只差 0.3 元,有時候差幾塊錢,有時候甚至差上百塊。
別看金額小,這個差異卻讓電腦公司拿不到尾款。因為客戶堅持:只要報表不能互相驗證,系統就算不上合格。
為了解決問題,軟體公司派了好幾位工程師進駐,日以繼夜地檢查程式與資料。直到有一天,財務小姐發現:「怎麼這裡多了一個 0.3 元?」那正好是一個彈簧配件的價格,庫存數量為 1,總價 0.3 元。
可是,為什麼總金額會因此差 0.3 元?大家百思不得其解。最後只好把整份庫存明細一筆一筆印出來比對。這才發現,這個彈簧配件在「總庫存表」裡被列了兩次。也就是說,它被計算了兩次,導致總金額多出了 0.3 元。
當這個「小蟲」被抓出來之後,把重複的資料刪掉,財務報表立刻與庫存總金額對上。真相大白:問題出在程式設計師撈資料時,沒有確保唯一性(uniqueness),結果造成一筆資料重複計算。
方格子平台上的 BUG,其實如出一轍
回到我們在方格子遇到的狀況:同一篇文章明明只寫一次,卻在後台出現兩份。這和剛才的彈簧案例如出一轍 ——

程式在抓取資料的時候,沒有處理「去重」與「唯一性」的問題。

這種情況在任何內容平台都可能發生,成因大致有幾類:
- 資料庫設計問題 沒有設定主鍵或唯一索引,導致同一筆資料被插入兩次。 查詢語法 join 多張表,結果出現多對多關係,數據倍增。
- 併發與提交問題 使用者在網路延遲時多按了幾次「發布」,後端沒有防護,結果產生兩篇相同文章。
- 異步任務重試 後台的同步工作在失敗後重跑,沒有檢查「該筆文章是否已存在」。
- 前後端不同步 前端 cache 與資料庫版本不一致,造成 UI 顯示上「看似有兩篇」。
這些問題的本質,都是沒有做好「唯一性檢查」。
解決方法:從資料到應用的全方位守門
要解決「重複文章」的問題,必須分層處理,不能只靠某一層。
1. 資料庫層 —— 保證唯一
- 給文章表設定主鍵(id)與唯一索引(slug、content_hash)。
- 使用複合唯一條件,例如 (author_id, title)。 SQL 範例:
ALTER TABLE articles ADD CONSTRAINT uq_articles_slug UNIQUE (slug);
ALTER TABLE articles ADD COLUMN content_hash VARCHAR(64);
CREATE UNIQUE INDEX uq_articles_content_hash ON articles(content_hash);
2. 寫入層 —— 避免重複插入
- 使用 transaction 確保一次請求只會建立一筆資料。
- 善用 upsert(Postgres 的 ON CONFLICT 或 MySQL 的 ON DUPLICATE KEY)。 範例:
INSERT INTO articles (slug, title, body, content_hash)
VALUES ($1, $2, $3, $4)
ON CONFLICT (content_hash) DO UPDATE SET title = EXCLUDED.title;
3. 應用層 —— 保持冪等
- 為每個請求生成 request id,避免多次提交。
- 透過文章內容的 hash 判斷是否已存在。 範例(Python 伪碼):
def create_article(request):
if exists_request_id(request.id): return existing_article
h = sha256(request.body)
article = db.find_one({'content_hash': h})
if article: return article
return insert_article(..., content_hash=h)
4. 顯示層 —— 查詢要去重
- 若因 join 導致一篇文章被拉回多次,記得 DISTINCT 或 GROUP BY。 範例:
SELECT DISTINCT a.id, a.title
FROM articles a
LEFT JOIN article_tags t ON t.article_id = a.id;
5. 維運層 —— 定期檢查
- 每日產生 資料品質報表,比對是否有相同 slug、hash 的文章。
- 提供後台工具,能快速合併或刪除重複文章。
結語:小小的 0.3 元,其實是系統設計的警鐘
那顆彈簧配件的 0.3 元,揭示了一個工程真理:哪怕最小的差異,背後都可能是程式設計上的缺口。
在方格子平台文章重複顯示的問題上,雖然對使用者來說只是困惑或不便,但對整個系統的資料一致性來說卻是警訊。
寫程式不只是「能跑就好」,而是要確保資料正確、唯一、能夠驗證。只有這樣,系統才能長久穩定,也不會因為一個小 bug,造成信任崩壞。
下次當你看到「怎麼同一篇文章出現兩次」時,或許可以笑著想:啊,這可能就是那個「0.3 元的彈簧」又出現了。

















