2013-05-18 1 views
1

Мой код:SQLiteDatabase.endTransaction бросает SQLiteDatabaseLockedException

SQLiteDatabase db = ...; 
db.beginTransaction(); 
try{ 
    db.update(...); 

    db.setTransactionSuccessful(); 
}finally{ 
    db.endTransaction(); 
} 

Теперь проблема заключается в том, что endTransaction иногда бросает SQLiteDatabaseLockedException, и я не знаю причину, или как повторить то же самое исключение.

От SQLiteDatabaseLockedException Я читаю:

Брошенный, если двигатель базы данных не удалось приобрести замки базы данных он должен делать свою работу.

И от beginTransaction Я читаю:

Начинает транзакцию в монопольном режиме.

От SQLite manual Я читаю:

монопольная блокировка необходима для того, чтобы писать в файл базы данных. В файл разрешен только один замок EXCLUSIVE, и никакие другие блокировки не могут сосуществовать с блокировкой EXCLUSIVE. Для того, чтобы максимизировать параллелизм, SQLite работает, чтобы свести к минимуму время, которое ЗАКЛЮЧЕНЫ ЭКСКЛЮЗИВ.

Как можно блокировать блокировку DB в endTransaction, когда я держу эксклюзивную блокировку от beginTransaction? Версия для Android, где это происходит, - 4.0.4 (у меня есть отчет о сбое, но я не могу повторить это).

Нужно сказать, что я включил SQLiteDatabase.enableWriteAheadLogging в БД, может быть, это имеет значение? БД для доступа к приложениям в нескольких потоках.

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

+0

Не должно быть: SQLiteDatabase db = new SQLiteDatabase(); – MrByte

+0

Обновлено до «...», чтобы отметить, что это уже инициализировано. –

+1

@PointerNull, как вам удалось это исправить? –

ответ

0

IMO ваш код верный в приложении с уникальной нитью, поэтому он должен быть связан с проблемой allowWriteAheadLogging. Может быть, это может помочь:

SOURCE

... Максимальное количество соединений, используемых для выполнения запросов в параллельно зависит от памяти устройства и, возможно, других свойств.

...

Авторы должны использовать beginTransactionNonExclusive() или beginTransactionWithListenerNonExclusive (SQLiteTransactionListener), чтобы начать транзакцию. Неисключительный режим позволяет файлу базы данных находиться в , читаемом другими потоками, выполняющими запросы.

...

0

Как я понимаю, в сериализуемом режиме (по умолчанию) в SQLite замки относятся не к разным потокам но соединений (этот режим даже ничего не знает о потоках). Таким образом, если вы используете одно и то же соединение (и все объекты SqliteDatabase, созданные одним экземпляром sqliteOpenHelper, используют одно и то же соединение) в нескольких потоках, вы совершенно незащищены.

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

Прочтите это extensive answer и ссылки на него для получения более подробной информации и передового опыта для многопоточности Sqlite.