你的位置:首页 > 数据库

[数据库]数据库损坏的可能原因


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