SQLite数据库损坏与修复
【引子】
平時(shí)用sqlite數(shù)據(jù)庫(kù)比較少。被問(wèn)到sqlite數(shù)據(jù)庫(kù)損壞怎么辦這個(gè)問(wèn)題時(shí)就把我難住了,于是就整合了幾篇比較好的文章,記錄一下。
SQLite算是非常穩(wěn)定的數(shù)據(jù)庫(kù),不容易出現(xiàn)損壞,就算應(yīng)用程序崩潰,或者操作系統(tǒng)崩潰,甚至是執(zhí)行事務(wù)時(shí)出現(xiàn)斷電,都能在下一次使用數(shù)據(jù)庫(kù)時(shí)自動(dòng)修復(fù)。但是,還是不能避免不出現(xiàn)損壞的情況。
導(dǎo)致SQLite數(shù)據(jù)庫(kù)損壞的情況
導(dǎo)致SQLite數(shù)據(jù)庫(kù)損壞的情況大致可歸結(jié)為4類:文件覆蓋問(wèn)題、文件鎖問(wèn)題、數(shù)據(jù)同步問(wèn)題、內(nèi)存問(wèn)題
文件覆蓋問(wèn)題
SQLite數(shù)據(jù)庫(kù)文件被覆蓋是可能的,畢竟是一個(gè)普通的磁盤文件,意味著所有的進(jìn)程都可以打開(kāi)和覆蓋,所以不可能完全避免文件覆蓋的情況。
1. 多線程寫數(shù)據(jù)庫(kù)問(wèn)題。
SQLite數(shù)據(jù)庫(kù)是支持多進(jìn)程并發(fā)讀寫,但是如果這時(shí)候關(guān)閉和重新打開(kāi)數(shù)據(jù)庫(kù),就很可能出現(xiàn)一些線程還在寫數(shù)據(jù)到數(shù)據(jù)庫(kù),出現(xiàn)部分?jǐn)?shù)據(jù)被覆蓋的情況。
2. 執(zhí)行事務(wù)時(shí)備份或恢復(fù)數(shù)據(jù)
事務(wù)都是一個(gè)過(guò)程性的操作,需要一定時(shí)間,而數(shù)據(jù)備份是原子操作,如果在事務(wù)執(zhí)行過(guò)程時(shí)備份,可能導(dǎo)致復(fù)制的內(nèi)容包含了部分新的內(nèi)容和部分舊的內(nèi)容,就出現(xiàn)數(shù)據(jù)庫(kù)損壞。恢復(fù)也是一樣。
3. 刪除日志文件
SQLite數(shù)據(jù)庫(kù)通常都是存儲(chǔ)所有內(nèi)容到一個(gè)文件,但執(zhí)行事務(wù)時(shí),為了實(shí)現(xiàn)程序崩潰,斷電時(shí)可以回滾日志,就伴隨著一些附加的日志文件。如果日志被刪除了,就會(huì)導(dǎo)致恢復(fù)出現(xiàn)異常。
文件鎖問(wèn)題
為了實(shí)現(xiàn)SQLite數(shù)據(jù)庫(kù)并發(fā)讀寫,SQLite會(huì)使用文件鎖來(lái)保證數(shù)據(jù)安全。
1. 系統(tǒng)文件鎖問(wèn)題
SQLite依賴于底層的文件系統(tǒng)對(duì)文件鎖的實(shí)現(xiàn),但是,一些文件系統(tǒng)存在鎖邏輯錯(cuò)誤,使得鎖并不可靠,這在網(wǎng)絡(luò)文件系統(tǒng)和NFS情況比較常見(jiàn)。
2. POSIX協(xié)同鎖(advisory lock)
在linux 或者unix下,SQLite 默認(rèn)鎖是協(xié)同鎖。當(dāng)進(jìn)程使用 協(xié)同鎖,如果其中有一個(gè)線程執(zhí)行 close() 就可能導(dǎo)致鎖被取消。如果已經(jīng)有兩個(gè)線程同時(shí)連接到同一個(gè)數(shù)據(jù)庫(kù),再來(lái)一個(gè)線程不以SQLite API的形式,就是以系統(tǒng)文件形式讀取數(shù)據(jù)庫(kù)( open(), read() , 然后close()),就會(huì)導(dǎo)致這個(gè)進(jìn)程的數(shù)據(jù)庫(kù)鎖被取消,而兩個(gè)線程同時(shí)操作數(shù)據(jù)庫(kù)就會(huì)導(dǎo)致數(shù)據(jù)覆蓋引起錯(cuò)亂。
3. 不同的連接協(xié)議
不同的 連接協(xié)議鎖也可能會(huì)不同,也就導(dǎo)致鎖沒(méi)有發(fā)揮錯(cuò)誤引起錯(cuò)誤。
4.當(dāng)數(shù)據(jù)庫(kù)正在使用時(shí)刪除或重命名數(shù)據(jù)庫(kù)文件
出現(xiàn)這種情況往往是在linux等類POSIX系統(tǒng),windows下不會(huì)出現(xiàn)這個(gè)情況,而且同時(shí)有事務(wù)執(zhí)行就會(huì)放大這個(gè)問(wèn)題。
數(shù)據(jù)同步問(wèn)題
為了保證數(shù)據(jù)一致性, SQLite有時(shí)候會(huì)請(qǐng)求操作系統(tǒng)將所有等待持久化的數(shù)據(jù)刷入磁盤,然后等待這個(gè)操作完成。
1.磁盤驅(qū)動(dòng)器的同步請(qǐng)求可能是不可靠的
現(xiàn)有普通消費(fèi)級(jí)別的磁盤驅(qū)動(dòng)器 多數(shù) 都會(huì)謊報(bào)數(shù)據(jù)同步結(jié)果,以期望得到更高的寫入速度。當(dāng)數(shù)據(jù)剛到達(dá)磁盤緩沖區(qū),還沒(méi)真正寫入氧化物介質(zhì),磁盤驅(qū)動(dòng)器就報(bào)告內(nèi)容已經(jīng)安全寫入。但是這時(shí)候斷電、硬件復(fù)位就會(huì)導(dǎo)致數(shù)據(jù)同步失敗。這種情況主要出現(xiàn)在閃存介質(zhì)。
2.使用PRAGMAs會(huì)影響同步
通過(guò)設(shè)置PRAGMA synchronous=OFF, SQLite所有的同步操作都會(huì)被忽略。這使得SQLite運(yùn)行得更快,但如果出現(xiàn)電源故障或硬件復(fù)位就會(huì)前面保存的所有數(shù)據(jù)。 如果單純?yōu)榱双@得最大的數(shù)據(jù)可靠性和健壯性,SQLite可設(shè)置synchronous = FULL
內(nèi)存問(wèn)題
SQLite作為一個(gè) C運(yùn)行庫(kù), 和使用它的應(yīng)用程序運(yùn)行在同一個(gè)內(nèi)存地址空間。這意味著,任何野指針,緩沖區(qū)溢出,堆損壞等都有可能損壞了 SQLite的數(shù)據(jù)結(jié)構(gòu),并最終導(dǎo)致數(shù)據(jù)庫(kù)文件損壞。
另外,使用內(nèi)存映射I/O模型(如mmap)的時(shí)候,內(nèi)存問(wèn)題會(huì)變得更加嚴(yán)重。當(dāng)數(shù)據(jù)庫(kù)文件的一部分或全部被映射到應(yīng)用程序的地址空間,雖然減少了文件IO操作,但是野指針可能訪問(wèn)并修改到任何部分的 映射空間 數(shù)據(jù)。
更多SQLite數(shù)據(jù)庫(kù)損壞的原因可以看官網(wǎng)
How To Corrupt An SQLite Database File。
1.1. Continuing to use a file descriptor after it has been closed
1.2. Backup or restore while a transaction is active
1.3. Deleting a hot journal
1.4. Mispairing database files and hot journals
2.1. Filesystems with broken or missing lock implementations
2.2. Posix advisory locks canceled by a separate thread doing close()
2.2.1. Multiple copies of SQLite linked into the same application
2.3. Two processes using different locking protocols
2.4. Unlinking or renaming a database file while in use
2.5. Multiple links to the same file
2.6. Carrying an open database connection across a fork()
3.1. Disk drives that do not honor sync requests
3.2. Disabling sync using PRAGMAs
4.1. Non-powersafe flash memory controllers
4.2. Fake capacity USB sticks
6.1. Linux Threads
6.2. Failures of mmap() on QNX
6.3. Filesystem Corruption
8.1. False corruption reports due to database shrinkage
8.2. Corruption following switches between rollback and WAL modes
8.3. I/O error while obtaining a lock leads to corruption
8.4. Database pages leak from the free page list
8.5. Corruption following alternating writes from 3.6 and 3.7.
8.6. Race condition in recovery on windows system.
修復(fù)損壞的SQLite數(shù)據(jù)庫(kù)
前陣子由于分區(qū)空間滿出現(xiàn)了sqlite3數(shù)據(jù)庫(kù)文件損壞的現(xiàn)象,操作的時(shí)候報(bào)錯(cuò):
Error: database disk image is malformed
這里記錄一下修復(fù)的操作過(guò)程:
1.將數(shù)據(jù)庫(kù)中的數(shù)據(jù)導(dǎo)出為sql語(yǔ)句文件
sqlite3 test_file.db #打開(kāi)損壞的數(shù)據(jù)庫(kù)文件 .output recovery.sql #設(shè)置輸出文件 .dump # 導(dǎo)出文件 .q2.將導(dǎo)出的recovery.sql文件最后一行ROLLBACK改為COMMIT;
vim recovery.sql3.導(dǎo)入到一個(gè)新庫(kù)中
sqlite3 fix.db #打開(kāi)用于導(dǎo)入修復(fù)后的數(shù)據(jù)庫(kù)數(shù)據(jù) .read recovery.sql #讀取數(shù)據(jù)文件 .qSQLite使用建議
這里有4點(diǎn)建議:
引經(jīng)據(jù)典
https://blog.csdn.net/jieshibendan/article/details/90678036
https://blog.csdn.net/qq_35241071/article/details/111247142
https://blog.csdn.net/mycwq/article/details/45541409
總結(jié)
以上是生活随笔為你收集整理的SQLite数据库损坏与修复的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 2020年中国餐饮配送机器人行业研究报告
- 下一篇: 查找最晚入职员工的所有信息---牛客网S