首先,一些背景知识:
我的 Android 应用包含有很多四列行的数据库表。它向服务器发送请求,服务器仅在所有这四个值都“有效”时才响应。数千名用户中的一些人报告说某些东西对他们不起作用(因为他们一段时间没有从服务器获得结果) - 我试图找出导致问题的原因,结果发现唯一可能的原因是数据库损坏未被检测到。
在ACRA日志中,我收到了一些带有SQL错误的消息,但这些消息是由于应用程序因为损坏而无法打开文件。这给了我一些线索,但我仍然不相信这是问题所在。所以,我创建了一个非常简单的Python脚本,它改变了DB文件中的随机字节,并检查SQLite将如何处理它:
import random
import array
import sqlite3
db = array.array('B')
db.fromstring(open('db').read())
ta = [x for x in sqlite3.connect('db').execute('SELECT * FROM table ORDER BY _id')]
results = [0,0,0,0]
tries = 1000
for i in xrange(0,tries):
work = db[:]
while work == db:
for j in xrange(0,random.randint(1,5)):
work[random.randint(1,len(db))-1] = random.randint(0,255)
work.tofile(open('outdb','w'))
try:
c = sqlite3.connect('outdb')
results[0] += 1
for r in c.execute('PRAGMA integrity_check;'):
results[1] += 1 if (r[0] == 'ok') else 0
except:
continue
try:
results[3] += 1 if [x for x in c.execute('SELECT * FROM table ORDER BY _id')] != ta else 0
results[2] += 1
except:
c.close()
continue
print 'Results for '+str(tries)+' tests:'
print 'Creating connection failed '+str(tries-results[0])+ ' times'
print 'Integrity check failed '+str(results[0]-results[1])+ ' times'
print 'Running a SELECT * query failed '+str(results[1]-results[2])+ ' times'
print 'Data was succesfully altered '+str(results[3])+ ' times'
结果显示以这种方式“编辑”表格数据是完全可能的:
Results for 1000 tests:
Creating connection failed 0 times
Integrity check failed 503 times
Running a SELECT * query failed 289 times
Data was succesfully altered 193 times
通常有趣的是,运行查询失败了一半未通过完整性检查检测到的修改,但对我来说最有趣的事情是,有些东西可能会在我的数据库中交换随机字节,导致我的应用程序无法使用我的用户。
我已经在SQLite网站和StackOverflow上了解了可能的腐败原因,我知道,例如强制关闭应用程序可能会对DB造成损害。我只想知道是否可以实现快速,更强大的数据库完整性检查。
我正在启动时从整个表的一列读取数据(用于自动完成),所以我想从所有值计算一些哈希值 - 我认为这样做会很好,因为一些哈希函数是设计好的只是为了进行完整性检查,但也许有一个更简单,更快速,更好的解决方案 - 我就是问你,如果你知道的话。