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