Intereting Posts
Как использовать интерфейс для связи между двумя действиями Android Studio 2.0 запускает APK на другом устройстве Пользовательские методы в решении RealmObjects …? Анимация RecyclerView не работает Плохая производительность с Guava Cache на Android Как создать Json с помощью JsonArray и JsonObject Как запретить VideoView / MediaPlayer останавливать звук других приложений? Сбой приложения Android при внесении изменений в базу данных Android: программно добавить элементы пользовательского интерфейса в представлении Можно ли запросить DownloadManager в потоке пользовательского интерфейса? Как перейти на более раннюю версию Gradle Android Studio ADB уничтожает файлы logcat при сбое приложения! Ohh Myy Импортировать библиотеку Google Play Services в Android Studio Robolectric 3.0, не удалось проверить функцию, которая запускает HandlerThread Использование метода updateAppWidgetOptions для AppWidgetManager для хранения параметров настройки виджета

Лучшее обнаружение коррупции SQLite

Во-первых, некоторый фон:

В моем Android- приложении есть таблица DB с множеством четырех столбцов. Он отправляет запросы на сервер, а сервер отвечает только тогда, когда все эти четыре значения являются «действительными». Несколько тысяч пользователей сообщили, что для них что-то не работает (с тех пор как они не получают результаты с сервера) – я пытался выяснить, что вызывает проблему, и оказалось, что единственной возможной причиной является Повреждение БД, которое не обнаружено.

В журналах 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, я знаю, что, например, принудительное закрытие приложения может нанести вред БД. Я просто хотел бы знать, возможно ли реализовать быструю и надежную проверку целостности БД.

Я читаю данные из одного столбца всей таблицы при запуске (для автозаполнения), поэтому я подумал о вычислении некоторого хеша из всех значений – я думаю, что это будет работать неплохо, поскольку некоторые хеш-функции предназначены только для выполнения Проверки целостности, но, возможно, есть более простое, быстрое и лучшее решение. Поэтому я спрашиваю вас, знаете ли вы.

    Я не знаю какой-либо подобной функции SQLite, поэтому я бы сказал, что вычисление хэша – это самое простое решение, для начала MessageDigest классом MessageDigest .