SQLite пишет database is locked: кто удерживает операцию
При database is locked сначала получите точный код SQLite и установите, какая операция конфликтует с текущей. SQLITE_BUSY обычно указывает на другое соединение, а SQLITE_LOCKED — на конфликт внутри того же соединения либо общего кэша. Удаление служебных файлов базы не устраняет причину и может нарушить восстановление.
Одна надпись скрывает разные ситуации
Оператор настольной программы нажал «Сохранить» и получил ошибку. Для разбора нужны действие, время, основной и расширенный коды, используемый драйвер. Не ограничивайтесь скриншотом: одинаковый текст в интерфейсе может скрывать разные детали отказа.
В справочнике кодов SQLite BUSY связан с конкурирующей активностью другого соединения, часто в другом процессе. LOCKED описывает конфликт того же соединения или соединения с shared cache. Другая программа — лишь один из возможных участников, а не обязательное объяснение.
Если приложение использует Microsoft.Data.Sqlite, его документация отдельно указывает свойства SqliteErrorCode и SqliteExtendedErrorCode. Для другого драйвера выясните соответствующий способ получить детали. Не переносите название настройки или поведение повтора между библиотеками автоматически.
Восстановите владельца и границы операции
Предлагаемая таблица — карта расследования для условной рабочей программы. Она не является выводом об открытых файлах или процессах пользователя. Заполнять её нужно наблюдениями приложения, не пытаясь снять блокировку удалением данных.
| Наблюдение | Кандидат на конфликт | Что попросить у разработчика | Безопасный следующий шаг | Чего это не доказывает |
|---|---|---|---|---|
| Ошибка при одновременном сохранении | Другое соединение с записью | Начало и завершение транзакций | Сопоставить интервалы работы | Что база повреждена |
| Ошибка в одном экземпляре программы | Собственное соединение или общий кэш | Полный код и незавершённые операции | Проверить жизненный цикл объектов | Что других соединений точно нет |
| Чтение отчёта пересекается с изменением | Долго удерживаемая работа | Когда закрывается результат чтения | Сократить ненужное удержание | Что любое чтение всегда блокирует запись |
| Ожидание заканчивается таймаутом | Конфликт не завершился вовремя | Кто ждёт и кто должен освободить ресурс | Разобрать причину ожидания | Что помогает бесконечный повтор |
| После штатного завершения ошибка исчезла | Освободилась операция | Какая работа завершилась | Исправить управление её границами | Что причина уже установлена навсегда |
Как транзакция становится длиннее бизнес-действия
Учебный сценарий: программа начала работу с базой, а затем ждёт внешнего ответа или решения пользователя. Такое ожидание стоит проверить на необходимость внутри транзакции. В задаче разработчику укажите не «ускорить SQLite», а отделить доступ к данным от несвязанной долгой работы, если это допускает логика.
Другой сценарий — результат чтения остаётся открыт дольше нужного. Проверьте, кто им владеет и когда он освобождается. Объект, который удобно хранить вместе с окном интерфейса, не обязательно должен жить столько же, сколько это окно.
Вместе с тем нельзя произвольно разрезать одну обязательную операцию на отдельные записи. Сначала определите требование к целостности. Сокращение времени удержания должно сохранять согласованное состояние данных, а не достигаться частичным сохранением заказа.
Таймаут даёт время, но не создаёт освобождение
Microsoft.Data.Sqlite автоматически повторяет busy/locked до успеха или таймаута команды. Это поведение конкретного провайдера. Если поверх него добавить собственный цикл повторов, суммарное ожидание нужно рассчитывать с учётом обоих уровней.
Увеличение таймаута может быть разумно для известного краткого пересечения работ. Оно не решает ожидание ресурса, который тот же код никогда не освободит. Зафиксируйте, какая операция должна завершиться и какое наблюдение подтверждает это завершение.
Пользователь должен видеть, идёт ли ограниченное ожидание или сохранение уже отклонено. Повторное нажатие кнопки не должно запускать независимые копии одной команды. Разработчик определяет допустимую границу повтора по коду ошибки и состоянию транзакции.
Почему WAL не делает всех одновременными писателями
В описании WAL SQLite чтение и запись могут выполняться одновременно, но писатель в один момент остаётся один. Поэтому включение WAL не является обещанием устранить любой конфликт. Совместимость режима с условиями хранения проверяется отдельно.
Если причина в долгой транзакции или неверном использовании соединения, сначала исправьте её. Смена режима без понимания текущей нагрузки лишь меняет условия, в которых ошибка проявляется. Для приёмки нужен тот же рабочий сценарий, который приводил к отказу.
Служебный файл рядом с базой — не мусорная блокировка
В руководстве SQLite о повреждении базы объяснена роль журналов при восстановлении после сбоя. Перемещение, удаление или переименование нужного журнала может помешать восстановлению. Это не способ заставить занятое соединение корректно завершить работу.
Не собирайте рабочую базу из случайной смеси файлов разных моментов. Если нужна копия для разбора, используйте согласованный безопасный способ резервирования. Перед передачей специалисту определите допустимые данные и доступ, вместо пересылки всей клиентской базы без подготовки.
Что включить в заявку и приёмку исправления
- Сохраните действие, время и полный доступный код ошибки.
- Определите драйвер, режим соединений и фактическую среду хранения.
- Сопоставьте начало и окончание конфликтующих работ.
- Проверьте освобождение результатов чтения и завершение транзакций.
- Опишите ограниченное ожидание и допустимую границу повторной попытки.
- На безопасной копии повторите конкурентный сценарий и штатное завершение.
- Проверьте целостный результат операции и понятное сообщение при отказе.
В поддержку приложения передайте воспроизведение без секретов и клиентских данных. Если потребуется изменение управления соединениями, оформите доработку. А при разработке новой десктопной программы согласуйте сценарии конкурентного доступа до выбора способа хранения.
Задача завершена, когда понятен владелец конфликтующей работы, исправлена её причина и проверен результат сохранения. Исчезновение сообщения после случайного перезапуска полезно как наблюдение, но не объясняет, почему следующий пользователь не встретит тот же отказ.
Вопросы и ответы
Чем SQLITE_BUSY отличается от SQLITE_LOCKED?
BUSY связан с другим соединением, а LOCKED — с конфликтом того же соединения либо общего кэша. Сохраняйте полный код: общая надпись database is locked недостаточна для выбора действия.
Поможет ли busy timeout убрать блокировку SQLite?
Ограниченное ожидание может помочь, если конфликтующая работа действительно заканчивается. Оно не исправляет операцию, которая удерживает ресурс из-за ошибки жизненного цикла.
Как разблокировать SQLite без удаления файлов базы?
Найдите и корректно завершите конфликтующую работу, затем устраните причину её лишнего удержания. Служебные журналы не удаляйте ради снятия сообщения: они могут быть нужны для восстановления.