Параллельное выполнение двух транзакций SQLite в двух потоках - PullRequest
1 голос
/ 25 июля 2011

В моем приложении для Android есть определенный метод обновления, который генерирует довольно много данных - до сотен записей в базе данных. У меня также есть фоновый сервис, кроме потока пользовательского интерфейса. Оба потока должны выполнять метод обновления, иногда даже в одно и то же время - в основном речь идет о генерации и кэшировании данных для отображения. Эти данные нужны и для пользовательского интерфейса, и для фоновой службы.

В настоящее время я завернул выполнение метода в транзакцию ORMLite, которая отображается на обычную транзакцию SQLite. Тем не менее, я боюсь, что это однажды укусит меня в задницу, когда какое-либо состояние гонки испортит кеш данных.

Вопрос: защищают ли транзакции SQLite меня от одновременного выполнения, или мне лучше реализовать какой-то рабочий поток, который создается при запуске метода генератора, или блокировать, если метод генератора уже запущен?

UPDATE:

Я решил не полагаться на логику SQLite для защиты моего высокоуровневого метода Java. Решение было для меня следующим:

  • Обернуть генерирующую часть метода с помощью synchronized
  • Введите переменную, которая отслеживает последний раз выполнения метода (устанавливается в конце метода, поэтому он является маркером выполнения END)
  • Первым делом в разделе synchronized проверьте, находится ли последнее выполнение в определенном пороге (например,
    • Если да, пропустить генерацию
    • Если нет, выполнить генерацию

Таким образом, генерация дубликатов не должна иметь место, поскольку, когда к методу обращаются одновременно из двух потоков, первый генерирует, а второй - нет. Самая важная часть для меня здесь заключается в том, что он все еще блокируется, поскольку оба потока полагаются на генерацию, которая произошла после того, как они вызвали метод.

1 Ответ

0 голосов
/ 25 июля 2011

EDIT:

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

Извините за вводящий в заблуждение ответ.

ПРОИСХОЖДЕНИЕ:

Хороший вопрос!

Здесь вы должны быть очень осторожны , поскольку стандартные объекты доступа к базе данных Android (такие как SQLiteDatabase, Cursor и т. Д.) По умолчанию не являются поточно-ориентированными. Даже ContentProvider, кажется, не дает вам полной защиты, если вы явно не напишите их с учетом многопоточности.

Согласно документации Android по ContentProvider и многопоточности (почти в конце страницы):

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

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

Возможно, вы могли бы попытаться реализовать какой-то одноэлементный объект (A ContentProvider, может быть?) Для доступа к вашей базе данных, но даже тогда вам, вероятно, придется управлять некой «очередью запросов».

Вам также следует учитывать , а не для любых вызовов файловой системы (база данных находится в файловой системе) из потока пользовательского интерфейса, что бы то ни было. Нет гарантии, что база данных ответит вовремя, и вы, скорее всего, получите ANR (особенно когда вы пишете "...which generates quite an amount of data").

...