返回
SQLiteDoctor 1.4.2.203免费版

SQLiteDoctor

立即下载

小编提示:PC版不适合移动端,如下载有问题点击反馈!

软件介绍

SQLiteDoctor是一款能够轻松修复sqlite数据库的专业软件。一款数据库管理人员都不会错过的sqlite数据库修复软件 SQLiteDoctor 。它使用起来非常简单,只需要选择sqlite数据库并输出要恢复的数据库文件。欢迎下载!

如何破坏sqlite数据库:

SQLite数据库非常耐腐败。如果应用程序崩溃,操作系统崩溃,甚至在事务中发生电源故障,则部分写入的事务应在下次访问数据库文件时自动回滚。恢复过程是完全自动的,不需要用户或应用程序执行任何操作。虽然SQLite可以抵御数据库损坏,但它并不是免疫的。本文档描述了SQLite数据库可能被破坏的各种方式。

1.该文件被流氓线程或进程覆盖

SQLite数据库文件是普通磁盘文件。这意味着任何进程都可以打开文件并用垃圾覆盖它。 SQLite库中没有任何内容可以防止这种情况。

1.1。关闭后继续使用文件描述符

我们已经看到在文件上打开了多个文件描述符,然后关闭文件描述符并在SQLite数据库上重新打开。稍后,一些其他线程继续编写旧文件描述符,而没有意识到原始文件已被关闭。但是由于SQLite重新打开文件描述符,用于输入原始文件的信息最终将覆盖某些SQLite数据库,从而导致数据库损坏。

其中一个例子发生在大约2013-08-30,在Fossil DVCS的规范库中。在这种情况下,文件描述符2(标准错误)在sqlite3_open_v2()之前被错误地关闭(我们怀疑它是stunnel),因此存储库数据库文件的文件描述符是2.稍后,应用程序错误导致断言的语句( )通过调用write(2,...)发出错误消息。但由于文件描述符2现在已连接到数据库文件,因此错误消息将覆盖数据库的一部分。为防止此类问题,SQLite版本3.8.1(2013-10-17)及更高版本拒绝对数据库文件使用低编号文件描述符。 (有关更多信息,请参阅SQLITE_MINIMUM_FILE_DESCRIPTOR。)

Facebook工程师在2014-08-12报道了另一个使用封闭文件描述符导致博客文章损坏的例子。

1.2。事务处于活动状态时备份或还原

在后台运行自动备份的系统可能会尝试在事务处理期间制作SQLite数据库文件的备份副本。然后,备份副本可能包含一些旧内容和一些新内容,并且将被破坏。

制作SQLite数据库的可靠备份副本的最佳方法是使用作为SQLite库一部分的备份API。如果不这样做,只要任何进程没有正在进行的事务,您就可以安全地复制SQLite数据库文件。如果上一个事务失败,则必须使用数据库文件本身复制任何回滚日志(* -journal文件)或预写日志(* -wal文件)。

1.3。删除流行的日记

SQLite通常将所有内容存储在单个磁盘文件中。但是,执行事务时,在崩溃或电源故障后恢复数据库所需的信息将存储在辅助日志文件中。此日志文件被描述为“热门”。日志文件与原始数据库文件具有相同的名称,并添加了-journal或-wal后缀。

SQLite必须查看日志文件以从崩溃或电源故障中恢复。如果在崩溃或电源故障后移动,删除或重命名热日志文件,则自动恢复将不起作用,并且数据库可能已损坏。

此问题的另一个表现是由于8 + 3文件名不一致导致数据库损坏。

1.4。不匹配的数据库文件和流行的期刊

前面的示例是一个更普遍的问题的特定情况:SQLite数据库的状态是控件

由数据库文件和日志文件引导。在静态状态下,日志文件不存在,只有数据库文件正确。但是,如果日志文件确实存在,则必须与数据库保持一致以避免损坏。以下操作可能导致损坏:

在两个不同数据库之间交换日志文件

使用其他日志文件覆盖日志文件。

将日志文件从一个数据库移动到另一个数

复制数据库文件而不复制其日志。

使用其他数据覆盖数据库文件,而不删除与原始数据库关联的任何热日志。

2.文件锁定问题

SQLite对数据库文件和预先编写的日志或WAL文件使用文件锁来协调并发进程之间的访问。如果没有协调,则两个线程或进程可能会尝试同时对数据库文件进行不兼容的更改,从而导致数据库损坏。

2.1。 Lock实现了损坏或丢失的文件系统

正如文档所述,SQLite依赖于底层文件系统来锁定。但是一些文件系统在其锁定逻辑中包含错误,因此锁定并不总是如所宣传的那样。对于网络文件系统和NFS尤其如此。如果在具有包含错误的锁定原语的文件系统上使用SQLite,并且如果两个或多个线程或进程尝试同时访问同一数据库,则可能导致数据库损坏。

2.2。 Posix顾问锁由一个单独的线程取消(close()

SQLite在Unix平台上使用的默认锁定机制是POSIX建议锁定。不幸的是,POSIX咨询锁具有设计怪癖,使其易受滥用和失败的影响。特别是,同一进程中具有保存POSIX顾问程序锁的文件描述符的任何线程都可以使用不同的文件描述符覆盖该锁。一个特别有害的问题是,对于进程中的所有线程和所有文件描述符,close()系统调用将取消同一文件上的所有POSIX顾问程序锁。

因此,例如,假设一个多线程进程有两个或多个线程,这些线程与同一个数据库文件具有不同的SQLite数据库连接。然后出现第三个线程,我想在不使用SQLite库的情况下从同一个数据库文件中读取内容。第三个线程执行open(),read()然后close()。人们会认为这将是无害的。但shutdown()系统调用会导致所有其他线程删除数据库中的锁。那些其他线程无法知道他们的锁刚被破坏(POSIX没有提供任何机制来确定这一点),所以他们继续运行,假设他们的锁仍然有效。这可能导致两个或多个线程或进程同时尝试写入数据库,从而导致数据库损坏。

请注意,两个或多个线程使用SQLite库访问同一SQLite数据库文件是完全安全的。 SQLite的Unix驱动程序知道POSIX顾问会锁定怪癖并修复它们。仅当线程尝试绕过SQLite库并直接读取数据库文件时,才会出现此问题。

2.2.1。多个SQLite副本链接到同一个应用程序

正如前一段所指出的,SQLite采取措施解决POSIX顾问程序锁定的怪癖。部分解决方法涉及保留开放SQLite数据库文件的全局列表(相互保护)。但是,如果SQLite的多个副本链接到同一个应用程序,则此全局列表将具有多个实例。使用SQLite库副本打开的数据库连接将不知道使用另一个副本打开的数据库连接,并且不会解决POSIX顾问程序锁定问题。 close()方法的连接操作可能在不知不觉中清除不同数据库连接上的锁,从而导致数据库损坏。

上面的场景听起来很牵强。但是,SQLite开发人员已经知道至少有一个商业产品刚刚发布了这个错误。供应商向SQLite开发人员寻求帮助,以跟踪他们在Linux和Mac上看到的一些不太常见的数据库损坏问题。此问题最终可追溯到应用程序连接两个单独的SQLite副本的事实。解决方案是将应用程序构建过程更改为仅链接一个SQLite副本而不是两个副本。

2.3。两个进程使用不同的锁定协议

SQLite在Unix平台上使用的默认锁定机制是POSIX建议锁定,但还有其他选项。通过使用sqlite3_open_v2()接口选择备用sqlite3_vfs,应用程序可以使用其他可能更适合某些文件系统的锁定协议。例如,您可以选择在必须在不支持POSIX建议锁定的NFS文件系统上运行的应用程序中使用点文件锁定。

对同一数据库文件的所有连接使用相同的锁定协议非常重要。如果应用程序正在使用POSIX咨询锁和另一个应用程序i

使用点文件锁定,两个应用程序将不会看到彼此的锁定,并且将无法协调数据库访问,这可能导致数据库损坏。

2.4。在使用时取消链接或重命名数据库文件

果两个进程具有到同一数据库文件的打开连接,并且进程关闭了它们的连接,则取消链接该文件,然后在其位置创建一个具有相同名称的新数据库文件并重新打开新文件,然后将两个进程一个数据库文件与同名将被传达给不同的流程。 (请注意,这仅适用于Posix和Posix类系统,它允许文件在读写时仍处于打开状态时取消链接.Windows不允许这样做。)由于回滚日志和WAL文件基于名称数据库文件,两个不同的数据库文件将共享相同的回滚日志或WAL文件。回滚或恢复其中一个数据库可能会使用其他数据库中的内容,从而造成损害。

换句话说,取消链接或重命名打开的数据库文件可能导致未定义的行为并且可能是不合需要的。

从SQLite版本3.7.17(2013-05-20)开始,如果数据库文件在仍在使用时取消链接,则unix OS界面将向错误日志发送SQLITE_WARNING消息。

2.5。指向同一文件的多个链接

如果单个数据库文件有多个链接(硬链接或软链接),那么这只是说该文件有多个名称的另一种方式。如果两个或多个进程使用不同的名称打开数据库,它们将使用不同的回滚日志和WAL文件。这意味着如果一个进程崩溃,另一个进程将无法恢复正在进行的事务,因为它将查找相应日志的错误位置。

换句话说,打开和使用具有两个或多个名称的数据库文件可能导致未定义的行为并且可能是不合需要的。

从SQLite版本3.7.17(2013-05-20)开始,如果数据库文件具有多个硬链接,则unix OS界面将向错误日志发送SQLITE_WARNING消息。

从SQLite版本3.10.0(2016-01-06)开始,unix OS界面将尝试按其规范名称解析符号链接和打开数据库文件。在3.10.0版之前,使用符号链接打开数据库文件类似于打开具有多个硬链接的数据库文件并导致未定义的行为。

2.6。跨fork()打开数据库连接

不要打开SQLite数据库连接,然后fork(),然后尝试在子进程中使用数据库连接。会导致各种锁定问题,并且您很容易遇到损坏的数据库。 SQLite不是为支持此行为而设计的。必须在子进程中打开子进程中使用的任何数据库连接,而不是从父进程继承。

如果在父进程中打开连接,则甚至不要在子进程的数据库连接上调用sqlite3_close()。关闭底层文件描述符是安全的,但sqlite3_close()接口可能会调用清除活动,这些活动将从父级中删除内容,从而导致错误甚至数据库损坏。

3.无法同步

为了确保数据库文件始终一致,SQLite偶尔要求操作系统将所有挂起的写入刷新到持久存储,然后等待刷新完成。这是使用Unix下的fsync()系统调用和Windows下的FlushFileBuffers()完成的。我们将此备用写入刷新称为“同步”。

实际上,如果您只关注原子和一致写入并且愿意放弃持久写入,则同步操作不需要等到内容完全存储在持久性介质上。相反,同步操作可视为I / O障碍。只要在同步之后发生的任何写入之前完成同步之前发生的所有写入,就不会发生数据库损坏。如果同步作为I / O障碍而不是真正的同步运行,则电源故障或系统崩溃可能导致一个或多个先前提交的事务被回滚(违反“

ACID的“持久性”属性)但数据库至少会继续保持一致,这是大多数人关心的。

SQLiteDoctor(sqlite数据库修复工具)

3.1。不支持同步请求的磁盘驱动器

不幸的是,大多数消费级大容量存储设备是同步的。一旦磁盘驱动器到达跟踪缓冲区并在实际写入氧化物之前报告内容,就可以安全地报告安全介质。这使得磁盘驱动器似乎运行得更快(这对于制造商来说非常重要,因此它们可以在贸易杂志中显示出良好的基准数据)。并且公平地说,只要在轨道缓冲器实际写入氧化物之前没有功率损耗或硬复位,谎言通常不会造成损坏。但是,如果确实发生了断电或硬复位,并且如果这导致在同步到达氧化物之后写入的内容并且在同步之前写入的内容仍在轨道缓冲器中,则可能发生数据库损坏。

USB闪存驱动器似乎是一个关于同步请求的特别恶毒的骗子。通过在USB记忆棒上向SQLite数据库提交大型事务,可以很容易地看到这一点。 COMMIT命令将相对快速地返回,表明记忆棒告诉操作系统并且操作系统告诉SQLite所有内容都安全地存在于持久存储中,但记忆棒末端的LED将继续闪烁一些更多秒。在LED仍在闪烁时拔出记忆棒通常会导致数据库损坏。

请注意,SQLite必须信任操作系统和硬件,以告知它有关同步请求状态的任何信息。 SQLite无法检测到任何人在说谎并且写入可能无序发生。但是,WAL模式下的SQLite对于无序写入比对默认回滚日志模式更宽松。在WAL模式下,失败的同步操作可能导致数据库损坏的唯一时间是在检查点操作期间。 COMMIT期间的同步失败可能导致耐久性丢失,但不会导致数据库文件损坏。因此,由于同步操作失败导致数据库损坏的防线是在WAL模式下使用SQLite并尽可能不频繁检查点。

3.2。使用PRAGMA禁用同步

同步编译指示可用于在运行时禁用SQLite执行以帮助确保完整性。通过设置PRAGMA synchronous = OFF,省略所有同步操作。这使得SQLite似乎运行得更快,但它也允许操作系统自由地重新排序写入,如果在所有内容到达持久存储之前发生电源故障或硬重置,则可能导致数据库损坏。

了最大限度地提高数据库损坏的可靠性和稳健性,SQLite应始终使用其默认同步设置运行FULL。

4.磁盘驱动器和闪存故障

如果由于磁盘驱动器或闪存故障导致文件内容发生更改,则SQLite数据库可能已损坏。这是非常罕见的,但磁盘偶尔会在该部门中间翻转。

4.1。非电源安全闪存控制器

我们被告知,在某些闪存控制器中,如果在写入期间电源中断,则损耗均衡逻辑可能导致随机文件系统损坏。例如,这可以表现为文件中间的随机变化,当电源关闭时,该文件甚至没有打开。因此,例如,当发生停电时,设备将内容写入闪存中的MP3文件,这可能导致SQLite数据库损坏,即使数据库在断电时未使用。

4.2。假容量USB棒

报告中有很多具有高容量的循环USB记忆棒(例如:8GB),但实际上只能存储少量(例如:1GB)。尝试在这些设备上写入通常会导致无关文件被覆盖。因此,任何使用欺诈性闪存设备都很容易导致数据库损坏。诸如“假容量usb”之类的互联网搜索将发现很多关于这个问题的令人不安的信息。

5.记忆腐败

SQLte是一个C库,它在与它所服务的应用程序相同的地址空间中运行。这意味着应用程序中的虚假指针,缓冲区溢出,堆损坏或其他故障可能会破坏内部SQLite数据结构,并最终导致数据库文件损坏。通常,在发生任何数据库损坏之前,这些类型的问题可能是分段错误,但在某些情况下,应用程序代码错误会导致SQLite失败,这可能会破坏数据库文件而不是恐慌。

使用内存映射I / O时,内存损坏问题会变得更严重。当全部或部分数据库文件映射到应用程序的地址空间时,覆盖该映射空间的任何部分的分支指针将立即销毁数据库文件,而不需要应用程序

形成后续的write()系统调用。

6.其他操作系统问题

有时,操作系统具有可能导致问题的非标准行为。有时,这种非标准行为是有意的,有时在实施中也是错误的。但无论如何,如果操作的执行方式与SQLite期望执行的方式不同,则可能会导致数据库损坏。

6.1。 Linux线程

一些旧版本的Linux使用LinuxThreads库来提供线程支持。 LinuxThreads类似于Pthreads,但在处理POSIX顾问程序锁时略有不同。 SQLite版本2.2.3到3.6.2认识到LinuxThreads正在运行并采取适当的步骤来解决LinuxThreads的非标准行为。但是大多数现代Linux实现都使用Pthreads更新,更准确的NPTL实现。从SQLite版本3.7.0(2010-07-21)开始,假设使用NPTL。没检查。因此,如果在使用LinuxThreads的旧Linux系统上运行的多线程应用程序中使用,最新版本的SQLite将会巧妙地失败并可能损坏数据库文件。

6.2。 QNX上的Mmap()失败了

QNX上的mmap()存在一些微妙的问题,它们对单个文件描述符进行第二次mmap()调用,该文件描述符将从第一个mmap()调用获得的内存归零。 Unix上的SQLite使用mmap()为WAL模式下的事务协调创建共享内存区域,并且它将为大事务多次调用mmap()。已证明QNX mmap()已在此方案中损坏数据库文件。 QNX工程师意识到了这个问题,正在研究解决方案;在阅读本文时,您可能已经解决了这个问题。

当QNX运行时,建议永远不要使用内存映射的I / O.此外,要使用WAL模式,建议应用程序使用独占锁定模式来使用没有共享内存的WAL。

6.3。文件系统损坏

于SQLite数据库是普通磁盘文件,因此文件系统中的任何故障都可能破坏数据库。现代操作系统中的文件系统非常可靠,但仍然会出现错误。例如,在2013-10-01,在主机被移动到文件系统层中有问题(linux)内核的黑客版本的几天后,销毁用于Tcl / Tk的Wiki的SQLite数据库被破坏。在这种情况下,文件系统最终损坏严重,无法使用该机器,但问题的第一个症状是SQLite数据库损坏。

7. SQLite配置错误

SQLite有许多内置的数据库损坏保护。但配置选项可以禁用许多这些保护。如果禁用保护,则可能发生数据库损坏。

以下是禁用SQLite内置保护机制的示例:

如果操作系统崩溃或电源故障,设置PRAGMA synchronous = OFF将导致数据库损坏,但此设置将避免应用程序崩溃造成的损坏。

打开其他数据库连接时更改PRAGMA schema_version。

使用PRAGMA journal_mode = OFF或PRAGMA journal_mode = MEMORY并在写入事务中使应用程序崩溃。

设置PRAGMA writable_schema = ON然后使用DML语句更改数据库模式可能会使数据库完全不可读,如果不仔细完成。

8. SQLite中的错误

SQLite经过了非常仔细的测试,以确保它尽可能没有错误。在针对每个SQLite版本执行的许多测试中,对模拟电源故障,I / O错误和内存不足(OOM)错误进行了一些测试,并验证了在任何这些事件期间都没有发生数据库损坏。 SQLite也经过现场验证,大约有20亿次活动部署,没有严重问题。

但是,没有软件100%完美。 SQLite中存在一些历史错误(现已修复),可能导致数据库损坏。还有一些尚未被发现。由于SQLite的广泛测试和广泛使用,导致数据库损坏的错误通常非常模糊。应用程序不太可能遇到SQLite错误。为了说明这一点,下面给出了一个帐户,列出了从2009-04-01到2013-04-15四年间在SQLite中发现的所有数据库损坏错误。该帐户应该让读者直观地了解SQLite中可以通过测试程序完成并使其成为版本的各种错误。

8.1。由于数据库收缩导致的虚假损坏报告

如果数据库是由SQLite 3.7.0或更高版本编写的,然后由SQLite 3.6.23或更早版本再次编写以减小数据库文件的大小,那么下一个SQLite版本3.7.0访问数据库文件它可能会报告数据库文件已损坏。但是,数据库文件并未真正损坏。版本3..0在腐败检测方面过于热情。

问题已在2011-02-20修复。这首先解决了

在SQLite版本3.7.6(2011-04-12)中发表。

8.2。在回滚和WAL模式之间切换后发生损坏

在进程或线程中重复切换进出WAL模式的SQLite数据库并在交换机之间运行VACUUM命令会导致打开数据库文件的另一个进程或线程错过数据库已更改的事实。然后,第二个进程或线程可能会尝试使用过时的缓存修改数据库并导致数据库损坏。

这个问题是在内部测试中发现的,从未在野外观察到过。该问题已在2011-01-27和3.7.5版本中得到修复。

8.3。获取锁定时的I / O错误可能会导致损坏

如果操作系统在尝试以WAL模式锁定共享内存时返回I / O错误,则SQLite可能无法重置其缓存,如果尝试后续写入,则可能导致数据库损坏。

请注意,只有在尝试获取导致I / O错误的锁时才会出现此问题。如果未授予锁定(因为某些其他线程或进程已经存在冲突锁定),则不会发生损坏。我们不知道在尝试获取共享内存上的文件锁时,任何操作系统都会因I / O错误而失败。所以这是一个理论问题,而不是真正的问题。不用说,在野外从未观察到这个问题。在模拟I / O错误的测试工具中对SQLite进行压力测试时发现了这个问题。

对于SQLite版本3.7.3,此问题已在2010-09-20修复。

8.4。数据库页面从空闲页面列表中泄漏

从SQLite数据库中删除内容时,不再使用的页面将添加到空闲列表中,并重新用于保存后续插入添加的内容。使用incremental_vacuum时,版本3.6.16到3.7.2中存在的SQLite中的错误可能导致页面在空闲列表之外丢失。这不会导致数据丢失。但这会导致数据库文件超出必要范围。并且它会导致integrity_check pragma报告空闲列表中缺少的页面。

对于SQLite版本3.7.2,此问题已在2010-08-23修复。

8.5。从3.6和3.7交替写入后的腐败。

SQLite版本3.7.0引入了许多SQLite数据库文件格式的新增强功能(例如但不限于WAL)。版本3.7.0是这些新功能的令人震惊的版本。我们期待找到问题,而不是失望。

如果数据库最初是使用SQLite版本3.7.0创建的,然后由SQLite版本3.6.23.1编写,则数据库文件的大小会增加,然后由SQLite版本3.7.0再次写入,数据库文件可能已损坏。

对于SQLite版本3.7.1,此问题已在2010-08-04中修复。

8.6。 Windows系统恢复的竞争条件。

SQLite版本3.7.16.2修复了Windows系统上锁定逻辑中的细微竞争条件。当需要恢复数据库文件时,因为写入它的先前进程在事务中间崩溃并且两个或多个进程尝试同时打开数据库,竞争条件可能导致其中一个进程获得表示恢复已完成的错误,允许进程继续使用数据库文件而不先运行恢复。如果进程写入文件,则该文件可能已损坏。所有以前版本的SQLite for Windows都明显存在这种竞争条件,可追溯到2004年。但竞争非常激烈。实际上,您需要一台快速的多核计算机,其中启动两个进程以同时在两个单独的核上运行恢复。此缺陷仅适用于Windows系统,不会影响posix OS界面。

SQLiteDoctor

软件要求:

MacOS 10.10.5或更高版本

Windows 7SP1 / 8.1 / 10或更高版本

软件功能:

易于使用的向导

要开始,只需选择要还原的sqlite数据库和输出数据库文件。如果损坏的数据库已加密,您可以选择设置加密密钥。

SQLiteDoctor支持所有标准的SEE sqlite加密:AES128,AES192和AES256。

SQLiteDoctor(sqlite数据库修复工具)

表格面板

扫描数据库以查找所有表和所有rowid值。如果找不到特定表的最大RowID值,则使用N / A值,您可以手动将该值设置为比您在数据库中对表所知的最大rowid值更高的值(如果不是输入的值) )使用的默认值是100000)。

恢复开始后,将生成详细的日志输出,以便您了解当前步骤。如果发生不可恢复的错误,将显示红色消息(带有总错误计数标签)。

精品推荐
猜你喜欢
用户评论