Watch at Ease看見世界,讀懂生活。

科技 · 實用指南

SQLite 備份完成就夠了嗎?輪替前重新開啟並驗證快照

備份呼叫完成只證明複製結束,不代表候選檔符合復原約定。以唯讀重開準確檔案,執行 SQLite 與應用檢查,安全提升後再輪替舊的可靠快照。

原創技術示意圖,展示建立、唯讀重開、SQLite 檢查、應用檢查、提升與延後輪替。
原創技術示意圖:準確候選檔通過結構、外鍵與應用檢查前,仍然只是候選。 Watch at Ease

SQLite 備份呼叫成功只是復原驗收的起點。先寫入唯一候選路徑,正確關閉目的端,再唯讀開啟這個準確檔案,避免檢查誤落到線上資料庫。

驗收同時需要引擎級與應用級證據。只有全部檢查通過才在目標檔案系統提升候選,並保留上一份可靠備份,直到提升後的檔案再次開啟成功。

1. 建立候選,而不是最終輪替目標

來源資料庫仍在使用或需要進度與分頁時,使用 SQLite 線上備份 API;Python 透過 Connection.backup() 提供它。VACUUM INTO 也能建立一致的緊湊快照,但輸出必須是新檔或空檔,中斷時仍可能留下不完整或損壞的檔案。

把候選寫入將要提升的目錄。活動 WAL 資料庫不應預設只複製主 .db 檔;若流程使用檔案複製,就要刻意停止寫入或處理所有必要伴隨檔。

2. 唯讀重新開啟準確候選

關閉目的連線後,用唯讀 URI 開啟候選本身。不要在來源連線上執行驗收查詢,也不要使用可能解析到線上資料庫的路徑別名。提升前記錄路徑、大小、雜湊、SQLite 與 Python 版本、建立方法及結果。

在 CPython 3.12.14、SQLite 3.53.1 的 Linux 測試中,Connection.backup() 候選可唯讀開啟;提升後又獨立重開目標路徑。這能抓到記憶體成功旗標無法發現的路徑錯誤。

3. 組合結構、外鍵與應用檢查

要求 PRAGMA quick_check 只回傳一列 ok,或在時間允許時執行更完整的 integrity_check。兩者都不驗證外鍵;SQLite 明確說明 integrity_check 不會找出外鍵錯誤,因此還要另外執行 foreign_key_check 並要求空結果。

接著驗證應用真正需要的復原約定:user_version 或遷移表、必要資料表與索引、已知哨兵資料、關鍵計數或不變量,以及代表性讀取。四列測試得到 quick_check=ok、無外鍵列和 sentinel=(sentinel, 3);破壞前16位元組的副本在重開時被拒絕。

4. 先提升,最後輪替舊副本

任何檢查失敗都要讓候選留在輪替集之外,保留上一份可靠備份,並記錄準確失敗查詢。不要原地修復候選後宣稱通過;重新建立快照才能保持來源清楚。結構檢查通過也不證明業務資料完整、最新或語意正確。

全部通過後,以同一檔案系統的重新命名或替換提升。Python 說明 os.replace 成功時具原子性,但跨檔案系統可能失敗。刪除或老化舊備份前,再開啟提升後路徑並重複最小哨兵檢查,同時定期在隔離環境驗證完整復原流程。

原創技術示意圖,比較線上備份 API、VACUUM INTO 與受控檔案複製並匯入共同驗收門。
原創技術示意圖:建立方法不同,但完成的候選都必須經過同一套重開與驗證。 Watch at Ease