版權聲明:博客將逐步遷移到 http://cwqqq.com https://blog.csdn.net/cwqcwk1/article/details/45541409
昨晚,朋友和我反饋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數據庫
linux下:
$ sqlite3 mydata.db ".dump" | sqlite3 new.db
win下:
d:\>sqlite3 mydata.db .dump > mydata.sql
d:\>sqlite3 new.db < mydata.sql
d:\>sqlite3 aa.db "pragma integrity_check"
固然,這些API只是在必定程序修復損壞的數據庫,沒法解決全部的問題。
SQLite使用建議
這裏有4點建議:
1. 減小多進程或多線程操做,儘量單線程寫。
2. 減小事務操做,減少事務複雜度,減小檢查點
3. 減小數據庫的大小
4. 避免使用PRAGMA synchronous=OFF