... после консультации с форумом SQLite ...
Решение:
Замените команду BEGIN TRANSACTION
на BEGIN IMMEDIATE TRANSACTION
.
Подробнее
В sqlite есть три типа транзакций:
- Deferred ( значение по умолчанию)
- Немедленно,
- Эксклюзивное
Если тип транзакции не указан явно в операторе BEGIN TRANSACTION
, то значение по умолчанию DEFERRED
выбран тип-транзакции.
В DEFERRED
тип-транзакции sqlite не будет пытаться получить какие-либо блокировки, пока не встретит первую команду, требующую этой блокировки.
Итак, если транзакция содержала одну команду READ и одну команду WRITE , тогда sqlite будет делать:
BEGIN TRANSACTION // No locks acquired
SELECT... // Try to acquire READ lock
INSERT... // Try to acquire WRITE lock
В мульти- потоковой среды, если вышеуказанная транзакция будет выполняться одновременно двумя (или более) разными потоками, может возникнуть взаимоблокировка:
- Thread-A a cquires READ lock,
- Thread-B получает READ lock,
- Thread-A пытается получить WRITE lock , который может быть получен только после того, как все блокировки READ и WRITE будут сняты,
- Thread-B пытается получить блокировку WRITE .. .
Это состояние является взаимоблокировкой , и, как объясняется в документации sqlite : если обнаружена потенциальная взаимоблокировка, то обработчик занятости не будет вызван как он не может разрешить это условие.
Выше описано, как работает DEFERRED
транзакция.
В обоих случаях - IMMEDIATE
и EXCLUSIVE
- блокировка WRITE приобретается прямо в начале транзакции , поэтому нет риска возникновения взаимоблокировок:
BEGIN IMMEDIATE TRANSACTION // Try to acquire the WRITE lock
SELECT... // ...no locks activity...
INSERT... // ...no locks activity...
Поскольку мой код использует sqlite в многопоточном режим многопоточности Мне пришлось заменить мою команду BEGIN TRANSACTION
на BEGIN IMMEDIATE TRANSACTION
.
Это решило проблему.