У меня есть приложение (Android 2.2, Google API Level 8), которое выполняет несколько операций, извлекающих данные у поставщика контента (ВЫБЕРИТЕ только доступ к базе данных).
Он также имеет службу с централизованной блокировкой очереди задач, принимающей любые задачи записи в базу данных; Операции могут запускать сервисный запрос (как намерение), который помещает задачу в очередь блокировки для последовательного извлечения одним потоком и выполнения. База данных составляет около 4 МБ.
Существует один помощник по базе данных, который служба использует для вызова методов для взаимодействия с базой данных, включая запись в нее; все записи SQL выполняются в помощнике по базе данных.
- Все записи в базу данных окружены транзакцией.
- Все чтения базы данных закрывают курсор в конце метода.
- Ни одна из операций не имеет дескриптора объекта базы данных, они могут взаимодействовать только через поставщика контента или службы.
- Любые задачи, запускаемые с помощью AlarmManager, например «Операции», используют эту службу только для добавления соответствующей задачи в очередь.
- Служба является единственным классом, который имеет дескриптор для помощника базы данных.
- Все записи в базу данных выполняются только через задачу, помещенную в очередь; Я тщательно проверил, что выполнение задачи является последовательным, хорошо зная, что важно избегать одновременных записей в базу данных SQLite.
Во время выполнения задач я последовательно получаю одну или две ошибки «база данных заблокирована» при попытке записи в базу данных, вызванную выполнением задачи «начать транзакцию».
При попытке отследить источник блокировки я обнаружил, что использование dbhelper.inTransaction (), dbhelper.isLockedByThisThread (), dbhelper.isLockedByOtherThread () не помогло, поскольку они не указывали бы на неожиданную блокировку базы данных.
Я обнаружил, что раннее обнаружение блокировки сработало в том, чтобы создать метод с beginTransaction () и setTransactionSuccessful без какого-либо реального кода записи SQL, в блоке try catch, который бы регистрировал проблему - всегда вызывается методом beginTransaction ().
Я поместил эту ловушку блокировки базы данных по обе стороны от каждого из методов задачи очереди блокировки в ожидании / надежде на то, что я найду единственного преступника, который оставит базу данных в заблокированном состоянии после завершения.
Я не мог найти последовательного виновника. После детализации от начала вызова задачи до записи в базу данных я обнаружил, что блокировка базы данных может происходить, по-видимому, совершенно неожиданно, не будучи заблокированной ранее выполненной задачей (Все эти задачи выполняются последовательно в одном единственном потоке ).
После изучения опыта других людей, связанных с блокировкой базы данных, я пытался закрыть соединение с базой данных сразу после завершения транзакции по всем задачам, но это не помогло, если что-то получало больше случаев блокировки базы данных. Попробовал добавить сон между каждым выполнением задачи; не был полностью протестирован, но, как правило, обнаружил, что задержка в 3 секунды или более, по-видимому, останавливает появление блокировок базы данных. Попытка отключения задач диспетчера тревог - без разницы.
У меня сложилось впечатление, что какая-то форма обслуживания, внешняя по отношению к моему приложению, периодически сбрасывает и блокирует базу данных - возможно, задерживает запись журналов. Очевидно, что я менее чем заинтересован в настройке задержки обработки задач, поэтому я рассматриваю вопрос об использовании очереди повторных попыток блокировки базы данных, чтобы при необходимости повторить попытку записи в базу данных; Я предпочитаю решать, но у меня заканчиваются идеи.
Кто-нибудь может вспомнить какой-то принцип или ошибку, которую я пропустил?
На самом ли деле в Android и более крупных базах данных SQLite нормально, что вы иногда получаете блокировки базы данных?
Спасибо