數據庫損壞的可能原因


1. 數據庫文件被其他線程覆蓋或刪除

  1. 在文件描述符關掉以后,繼續使用這個文件描述符訪問
    1. 打開文件,獲取文件描述符fd(其實是一個整形)
    2. 關閉文件
    3. 打開sqlite文件,獲取文件描述符(碰巧也是)fd
    4. 另一個線程繼續使用fd,寫文件
    5. sqlite文件被損壞
  2. 在事務進行過程中,進行數據庫備份或恢復
    在數據庫事務過程中,數據庫文件既包括老的內容,也包括新的內容。如果此時拷貝這個文件,數據庫可能會被損壞。 備份數據庫最好使用sqlite的api
  3. 刪除日志文件
    日志文件中包括rollback需要的信息。刪除以后,無法正確回滾,有可能會導致數據庫損壞。

2. 文件鎖相關

sqlite使用文件鎖來在保證多線程訪問。如果文件鎖機制不正常,會導致同時讀寫文件等信息,導致數據庫損壞

  1. 文件系統沒有正確的實現文件鎖的機制
    在網絡操作系統中,比較常見
  2. 不正確使用close()函數
    在Unix中,close()函數會解除所有線程的文件鎖。
    例如A、B線程打開了數據庫文件,使用sqlite的api。此時,線程C依次調用了open(),read()以及close()。此時,這個文件的所有鎖已經沒了。因此A、B有可能會同時寫數據到文件中。
  3. 兩個進程使用不同的鎖協議(locking protocols)
    默認使用POSIX advisory locking,可以用sqlite3_open_v2()函數修改。如果不一致,可能發生同時讀寫,數據庫損壞。
  4. 在數據庫文件使用時rename或unlink
    兩個進程A、B,同時對一個數據庫文件建立數據庫連接。A關閉連接,unlink文件,用同樣的名字創建一個新的數據庫文件,在打開這個數據庫。這樣子A、B兩個進程在使用不同的數據庫,名字卻是一樣的。 然而,日志文件是根據數據庫名字來區分數據庫文件的。因此這兩個進程的數據庫文件會是同一個。導致數據庫文件損壞。
  5. 一個文件有多個連接
    也就是說一個數據庫文件有多個名字。假如A、B使用不同的名字打開同一個數據庫鏈接,會有兩個日志文件。 如果線程A crash了,B檢測到需要進行rollback。找不到日志文件,無法回滾。

3. sync失敗

為了保證數據庫文件的一致性(consistent),會調用fsync()系統調用,把內存中的數據刷到磁盤中。如果這個sync操作失敗,會導致數據庫文件損壞

  1. sync系統調用和文檔描述不一致
    USB閃存經常這樣子。例如寫大數據時,在函數返回已寫入成功時,USB的指示燈還在亮着。
  2. 使用PRAGMAs禁用sync
    synchronous=OFF可以提高速度,卻會導致文件不一致。

4. 硬盤、閃存損壞

5. 內存損壞

當野指針、內存溢出等原因,可能導致內存中的數據庫結構損壞,從而有可能導致數據庫文件損壞。
當進行memory-mapped I/O時,由於內存直接映射到磁盤,如果發生數組越界等,內存中的數據損壞,磁盤文件也會損壞

6. 其他操作系統問題

  1. 文件系統崩潰 ##7.sqlite的bug


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM