昨晚,朋友和我反馈sqlite数据库发生损坏有没有办法恢复。大致的情况是这样的,当数据库在使用时不小心用了新的文件覆盖数据库,导致了sqlite数据库出现了损坏,打开的时候出现要输入密码,而且不能把sql语句dump下来。所以,文章这里整理sqlite数据库出现损坏的所有情况,以及如何修复损坏的sqlite数据库文件。
导致sqlite数据库损坏的情况
文件覆盖问题
1. 多线程写数据库问题。
2. 执行事务时备份或恢复数据
文件锁问题
1. 系统文件锁问题
2. POSIX协同锁(advisory lock)
在linux 或者unix下,sqlite 默认锁是协同锁。当进程使用
协同锁,如果其中有一个线程执行 close() 就可能导致锁被取消。如果已经有两个线程同时连接到同一个数据库,再来一个线程不以sqlite API的形式,就是以系统文件形式读取数据库( open(),read(),然后close()),就会导致这个进程的数据库锁被取消,而两个线程同时操作数据库就会导致数据覆盖引起错乱。
3. 不同的连接协议
出现这种情况往往是在linux等类POSIX系统,windows下不会出现这个情况,而且同时有事务执行就会放大这个问题。
数据同步问题
为了保证数据一致性,
sqlite有时候会请求操作系统将所有等待持久化的数据刷入磁盘,然后等待这个操作完成。
1.磁盘驱动器的同步请求可能是不可靠的
现有普通消费级别的磁盘驱动器
多数
都会谎报数据同步结果,以期望得到更高的写入速度。当数据刚到达磁盘缓冲区,还没真正写入氧化物介质,磁盘驱动器就报告内容已经安全写入。但是这时候断电、硬件复位就会导致数据同步失败。这种情况主要出现在闪存介质。
2.使用PRAGMAs会影响同步
通过设置PRAGMA synchronous=OFF, sqlite所有的同步操作都会被忽略。这使得sqlite运行得更快,但如果出现电源故障或硬件复位就会前面保存的所有数据。
如果单纯为了获得最大的数据可靠性和健壮性,sqlite可设置synchronous = FULL
内存问题
另外,使用内存映射I/O模型(如mmap)的时候,内存问题会变得更加严重。当数据库文件的一部分或全部被映射到应用程序的地址空间,虽然减少了文件IO操作,但是野指针可能访问并修改到任何部分的
映射空间
数据。
修复损坏的sqlite数据库
linux下:
win下:
d:\>sqlite3 aa.db "pragma integrity_check"
这里可以下载
sqlite3.exe
sqlite使用建议
这里有4点建议:
1. 减少多进程或多线程操作,尽可能单线程写。
2. 减少事务操作,减小事务复杂度,减少检查点
3. 减少数据库的大小
4. 避免使用PRAGMA synchronous=OFF
转自:http://blog.csdn.net/mycwq/article/details/45541409