【问题标题】:Recovering database rows from an uncommitted transaction从未提交的事务中恢复数据库行
【发布时间】:2010-12-14 23:34:15
【问题描述】:
我们有一个由 Python 编写的程序写入的数据库,该程序使用 sqlite3 模块。数据库执行了大量的插入语句,但事务从未被提交结束。
结果是我们有两个文件:
Size Time Name
855117824 2010-12-14 15:27 db
1665240 2010-12-14 15:27 db-journal
数据库文件很大,但是大部分数据是未提交的,所以当我们从数据库中选择时,我们只能得到几行。当我们执行 sql 命令 'VACUUM' 时,数据库缩小到大约 3MB。
有没有办法找回数据?
【问题讨论】:
标签:
sql
database
sqlite
pysqlite
【解决方案1】:
我使用sqlite3 shell 程序进行了一些测试。
假设 sqlite3 Python 模块的行为方式相同,似乎没有办法可靠地恢复未提交的事务。
对于相对少量的语句,未提交的事务似乎只完全保留在应用程序内存中,没有数据写入文件系统。一旦数据库连接关闭或应用程序终止,这些插入将完全丢失。
对于较大的事务块,数据写入文件系统,但一旦关闭数据库连接或(如果应用程序崩溃)下次打开数据库时,数据就会被清除。简单来说,为未提交的事务分配新的 DB 页,但如果未提交事务,则它们被视为可用空间,这就是 VACUUM 减小 DB 大小的原因。这些页面将在下次写入 DB 文件时被写入(并且它们的数据会丢失)。如果它们位于 DB 文件的末尾,则文件会在清理时被截断。
您可能能够从上次执行的未提交事务中恢复一些数据,只要之后没有执行其他写入事务。从您的问题的措辞方式来看,听起来好像整个数据库都是在单个程序运行和单个事务中创建和填充的(尽管 VACUUM 那时不会产生这么大的文件)。在这种情况下,事情可能会容易一些。
这在很大程度上取决于行为不端的程序是如何终止的。如果您允许它正常终止,它可能有时间进行清理,在这种情况下这是不可取的。既然你有 DB 日志,我会假设它有一个更暴力的结局。
无论如何,您至少必须深入研究 sqlite3 DB 文件格式并修改库代码以解析未提交的数据。您仍然会丢失保留在应用程序内存中的那些事务部分。
如果数据库文件中有空闲页面(例如来自DELETE 语句),则可能还有旧事务的片段,尽管解释这些片段是另一回事。
在我看来,整个操作将过于接近(如果不是直接进入)计算机取证和数据恢复领域以及所有相关问题。除非您有其他任何方式都无法获得的非常重要的数据,否则我怀疑这是否足够容易,值得费心。