Простым методом проб и ошибок я обнаружил, что они пошли по пути ошибки.
В данном сценарии, когда B пытается взять RESERVED, он сначала будет ждать PRAGMA busy_timeout
миллисекунды. Тогда он сообщит Error: database is locked
. Транзакция все еще будет активной, поэтому возможна немедленная повторная попытка.
Если A впоследствии попытается COMMIT
(или если у него закончится кэш в памяти), он возьмет блокировку PENDING (предотвращая дополнительные блокировки SHARED), а затем дождется EXCLUSIVE. Если некоторые блокировки SHARED остаются через PRAGMA busy_timeout
миллисекунд, он выдаст сообщение Ошибка: база данных заблокирована . Транзакция будет по-прежнему активной, поэтому возможна немедленная повторная попытка.
Другими словами, используемый механизм предотвращения тупиковых ситуаций - это тайм-аут. Однако для этого требуется, чтобы пользователи API сотрудничали, откатившись и повторив попытку.
В качестве ориентира:
- Используйте только
BEGIN TRANSACTION
(или явно BEGIN DEFERRED TRANSACTION
), когда ожидаете только чтения. Возможно, запись может завершиться неудачей, что приведет к откату и повторной попытке всей транзакции.
- Используйте
BEGIN IMMEDIATE TRANSACTION
, когда вы ожидаете, возможно, написать в какой-то момент. Это заблокирует всех других писателей и всех других непосредственных, возможно, писателей.
BEGIN EXCLUSIVE TRANSACTION
немедленно заблокируется, пока не будут сняты все другие блокировки. Я понятия не имею, почему кто-то хотел бы этого. Возможно, чтобы подготовиться к некоторым данным, которые должны быть записаны на диск как можно быстрее после их поступления? РЕДАКТИРОВАТЬ: Кажется, это единственный способ предотвратить тайм-ауты в произвольных точках после начала транзакции.