Android sqlite: «база данных заблокирована», ошибки, несмотря на использование поставщика контента и последовательный доступ к базе данных

У меня есть приложение (Android 2.2 Google API уровня 8), в котором несколько действий извлекают данные от поставщика контента (только для базы данных SELECT доступ). В нем также есть служба с центральной блокирующей очередью задач, которая принимает любые задачи записи в базу данных; Действия могут запускать запрос на обслуживание (как намерение), который помещает задачу в очередь блокировки для последовательного извлечения одним потоком и выполнения. База данных составляет около 4 МБ.

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

  • Все операции записи в базу данных заключаются в транзакции.
  • Все чтения из базы данных закрывают курсор в конце метода.
  • Ни одно из действий не имеет дескриптора объекта базы данных, они могут взаимодействовать только через поставщика контента или службу.
  • Любые задачи, запускаемые AlarmManager - например, Действия - используют службу только для помещения соответствующей задачи в очередь.
  • Служба - единственный класс, у которого есть дескриптор помощника базы данных.
  • Все записи в базу данных выполняются только с помощью задачи, помещенной в очередь; Я исчерпывающе проверил, что выполнение задачи является последовательным, хорошо осознавая, что это важно, чтобы избежать одновременной записи в базу данных SQLite.

Во время выполнения задач я постоянно получаю одну или две ошибки «база данных заблокирована» при попытке записи в базу данных, вызванных выполнением задачи «начать транзакцию».

Пытаясь отследить источник блокировки, я обнаружил, что использование dbhelper.inTransaction (), dbhelper.isLockedByThisThread (), dbhelper.isLockedByOtherThread () не помогает, поскольку они не указывают на неожиданную блокировку базы данных.

Я обнаружил, что сработало для раннего обнаружения блокировки, так это создание метода с beginTransaction () и setTransactionSuccessful без какого-либо фактического кода записи SQL в блоке try catch, который регистрировал проблему - всегда запускается beginTransaction ().

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

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

У меня сложилось впечатление, что какая-то внешняя по отношению к моему приложению задача обслуживания периодически блокируется и блокирует базу данных - возможно, с задержкой записи журналов. Очевидно, я не очень заинтересован в установке задержки обработки задачи, поэтому я рассматриваю возможность создания очереди задач повтора блокировки базы данных для повторной попытки записи в базу данных по мере необходимости; я предпочитаю разрешить, но у меня заканчиваются идеи.

Кто-нибудь может придумать какой-нибудь принцип или ошибку, которую я пропустил?

Является ли в действительности нормальным в Android и более крупных базах данных SQLite случайные блокировки базы данных?

Спасибо

10
задан Eveys 31 October 2011 в 14:25
поделиться