討論SQLite資料庫損壞與修複,討論sqlite資料庫
昨晚,朋友和我反饋SQLite資料庫發生損壞有沒有辦法恢複。大致的情況是這樣的,當資料庫在使用時不小心用了新的檔案覆蓋資料庫,導致了SQLite資料庫出現了損壞,開啟的時候出現要輸入密碼,而且不能把SQL語句dump下來。所以,文章這裡整理SQLite資料庫出現損壞的所有情況,以及如何修複損壞的SQLite資料庫檔案。
SQLite算是非常穩定的資料庫,不容易出現損壞,就算應用程式崩潰,或者作業系統崩潰,甚至是執行事務時出現斷電,都能在下一次使用資料庫時自動修複。但是,還是不能避免不出現損壞的情況。
導致SQLite資料庫損壞的情況導致SQLite資料庫損壞的情況大致可歸結為4類:檔案覆蓋問題、檔案鎖問題、資料同步問題、記憶體問題
檔案覆蓋問題SQLite資料庫檔案被覆蓋是可能的,畢竟是一個普通的磁碟檔案,意味著所有的進程都可以開啟和覆蓋,所以不可能完全避免檔案覆蓋的情況。1. 多線程寫資料庫問題。 SQLite資料庫是支援多進程並發讀寫,但是如果這時候關閉和重新開啟資料庫,就很可能出現一些線程還在寫資料到資料庫,出現部分資料被覆蓋的情況。
2. 執行事務時備份或恢複資料 事務都是一個過程性的操作,需要一定時間,而資料備份是原子操作,如果在事務執行過程時備份,可能導致複製的內容包含了部分新的內容和部分舊的內容,就出現資料庫損壞。恢複也是一樣。
3. 刪除記錄檔 SQLite資料庫通常都是儲存所有內容到一個檔案,但執行事務時,為了實現程式崩潰,斷電時可以復原日誌,就伴隨著一些附加的記錄檔。如果日誌被刪除了,就會導致恢複出現異常。
檔案鎖問題為了實現SQLite資料庫並發讀寫,SQLite會使用檔案鎖來保證資料安全。1. 系統檔案鎖問題SQLite依賴於底層的檔案系統對檔案鎖的實現,但是,一些檔案系統存在鎖邏輯錯誤,使得鎖並不可靠,這在網路檔案系統和NFS情況比較常見。
2. POSIX協同鎖(advisory lock)在linux 或者unix下,SQLite 預設鎖是協同鎖。當進程使用協同鎖,如果其中有一個線程執行 close() 就可能導致鎖被取消。如果已經有兩個線程同時串連到同一個資料庫,再來一個線程不以SQLite API的形式,就是以系統檔案形式讀取資料庫( open(), read() , 然後close()),就會導致這個進程的資料庫鎖被取消,而兩個線程同時操作資料庫就會導致資料覆蓋引起錯亂。
3. 不同的連線協定不同的連線協定鎖也可能會不同,也就導致鎖沒有發揮錯誤引起錯誤。
4.當資料庫正在使用時刪除或重新命名資料庫檔案出現這種情況往往是在linux等類POSIX系統,windows下不會出現這個情況,而且同時有事務執行就會放大這個問題。
資料同步問題為了保證資料一致性,SQLite有時候會請求作業系統將所有等待持久化的資料刷入磁碟,然後等待這個操作完成。1.磁碟機的同步請求可能是不可靠的 現有普通消費層級的磁碟機多數都會謊報資料同步結果,以期望得到更高的寫入速度。當資料剛到達磁碟緩衝區,還沒真正寫入氧化物介質,磁碟機就報告內容已經安全寫入。但是這時候斷電、硬體複位就會導致資料同步失敗。這種情況主要出現在快閃記憶體介質。
2.使用PRAGMAs會影響同步通過設定PRAGMA synchronous=OFF, SQLite所有的同步操作都會被忽略。這使得SQLite運行得更快,但如果出現電源故障或硬體複位就會前面儲存的所有資料。如果單純為了獲得最大的資料可靠性和健壯性,SQLite可設定synchronous = FULL
記憶體問題SQLite作為一個C運行庫,和使用它的應用程式運行在同一個記憶體位址空間。這意味著,任何野指標,緩衝區溢位,堆損壞等都有可能損壞了SQLite的資料結構,並最終導致資料庫檔案損壞。另外,使用記憶體對應 I/O模型(如mmap)的時候,記憶體問題會變得更加嚴重。當資料庫檔案的一部分或全部被映射到應用程式的地址空間,雖然減少了檔案IO操作,但是野指標可能訪問並修改到任何部分的映射空間資料。
更多SQLite資料庫損壞的原因可以看這裡。
修複損壞的SQLite資料庫linux下:$ sqlite3 mydata.db ".dump" | sqlite3 new.dbwin下:d:\>sqlite3 mydata.db .dump > mydata.sqld:\>sqlite3 new.db < mydata.sqld:\>sqlite3 aa.db "pragma integrity_check"
這裡可以下載 sqlite3.exe當然,這些API只是在一定程式修複損壞的資料庫,無法解決所有的問題。
SQLite使用建議這裡有4點建議:1. 減少多進程或多線程操作,儘可能單線程寫。2. 減少事務操作,減小事務複雜度,減少檢查點3. 減少資料庫的大小4. 避免使用PRAGMA synchronous=OFF
參考:http://blog.csdn.net/mycwq/article/details/45541409