1. 數據庫文件被其他線程覆蓋或刪除
- 在文件描述符關掉以后,繼續使用這個文件描述符訪問
- 打開文件,獲取文件描述符fd(其實是一個整形)
- 關閉文件
- 打開sqlite文件,獲取文件描述符(碰巧也是)fd
- 另一個線程繼續使用fd,寫文件
- sqlite文件被損壞
- 在事務進行過程中,進行數據庫備份或恢復
在數據庫事務過程中,數據庫文件既包括老的內容,也包括新的內容。如果此時拷貝這個文件,數據庫可能會被損壞。 備份數據庫最好使用sqlite的api。 - 刪除日志文件
日志文件中包括rollback需要的信息。刪除以后,無法正確回滾,有可能會導致數據庫損壞。
2. 文件鎖相關
sqlite使用文件鎖來在保證多線程訪問。如果文件鎖機制不正常,會導致同時讀寫文件等信息,導致數據庫損壞
- 文件系統沒有正確的實現文件鎖的機制
在網絡操作系統中,比較常見 - 不正確使用close()函數
在Unix中,close()函數會解除所有線程的文件鎖。
例如A、B線程打開了數據庫文件,使用sqlite的api。此時,線程C依次調用了open(),read()以及close()。此時,這個文件的所有鎖已經沒了。因此A、B有可能會同時寫數據到文件中。 - 兩個進程使用不同的鎖協議(locking protocols)
默認使用POSIX advisory locking,可以用sqlite3_open_v2()函數修改。如果不一致,可能發生同時讀寫,數據庫損壞。 - 在數據庫文件使用時rename或unlink
兩個進程A、B,同時對一個數據庫文件建立數據庫連接。A關閉連接,unlink文件,用同樣的名字創建一個新的數據庫文件,在打開這個數據庫。這樣子A、B兩個進程在使用不同的數據庫,名字卻是一樣的。 然而,日志文件是根據數據庫名字來區分數據庫文件的。因此這兩個進程的數據庫文件會是同一個。導致數據庫文件損壞。 - 一個文件有多個連接
也就是說一個數據庫文件有多個名字。假如A、B使用不同的名字打開同一個數據庫鏈接,會有兩個日志文件。 如果線程A crash了,B檢測到需要進行rollback。找不到日志文件,無法回滾。
3. sync失敗
為了保證數據庫文件的一致性(consistent),會調用fsync()系統調用,把內存中的數據刷到磁盤中。如果這個sync操作失敗,會導致數據庫文件損壞
- sync系統調用和文檔描述不一致
USB閃存經常這樣子。例如寫大數據時,在函數返回已寫入成功時,USB的指示燈還在亮着。 - 使用PRAGMAs禁用sync
synchronous=OFF可以提高速度,卻會導致文件不一致。
4. 硬盤、閃存損壞
5. 內存損壞
當野指針、內存溢出等原因,可能導致內存中的數據庫結構損壞,從而有可能導致數據庫文件損壞。
當進行memory-mapped I/O時,由於內存直接映射到磁盤,如果發生數組越界等,內存中的數據損壞,磁盤文件也會損壞
6. 其他操作系統問題
- 文件系統崩潰 ##7.sqlite的bug
