Ошибка database is locked в SQLite
SQLite пишет database is locked, когда другое подключение держит открытую транзакцию с изменениями. В SQLite писать в базу может только одно подключение за раз, остальные ждут. Если ждать пришлось дольше заданного времени — эта ошибка. Решение — найти, кто держит базу, и завершить его транзакцию.
Кто держит базу
Чаще всего это одно из:
- DB Browser for SQLite с незаписанными изменениями. Пока не нажата «Write Changes» или «Revert Changes», программа держит транзакцию, и никто другой писать в файл не может. Нажмите одну из кнопок или закройте программу.
- Открытая транзакция в
sqlite3. ПослеBEGINне былоCOMMITилиROLLBACK. Наберите в том окне нужную команду. - Программа без commit. Модуль
sqlite3в Python сам открывает транзакцию передINSERT,UPDATEиDELETEи держит её доcommit(). Если программа выполнила изменение и долго работает дальше, база занята всё это время. - Две программы пишут одновременно, например сайт и скрипт импорта, и транзакции у них долгие.
- База на сетевом диске. Блокировка файлов по сети (общие папки Windows, NFS) работает ненадёжно — держите базу на локальном диске компьютера, где работает программа.
В Linux программы, у которых открыт файл, показывает команда lsof shop.db (или fuser shop.db).
Не удаляйте файлы shop.db-journal и shop.db-wal рядом с базой, чтобы «снять блокировку». В них лежат данные незавершённой или ещё не перенесённой в базу транзакции. Без них база может оказаться испорченной или потерять последние изменения. Блокировку снимает только завершение транзакции или закрытие программы.
Как избежать
Короткие транзакции. Открыли, изменили, зафиксировали — сразу. Не держите транзакцию, пока программа ждёт ввода, скачивает файл или делает долгие расчёты. В Python удобно так:
import sqlite3
con = sqlite3.connect("shop.db", timeout=10)
with con:
con.execute("UPDATE products SET qty = qty - 1 WHERE id = 3")
con.close()Блок with con: сам вызывает commit(), если всё прошло, и rollback() при ошибке.
Время ожидания. timeout=10 — подождать до 10 секунд, пока база освободится, и только потом выдать ошибку (по умолчанию в Python — 5 секунд). В самом SQLite то же задаёт команда:
PRAGMA busy_timeout = 10000;Значение — в миллисекундах, действует на текущее подключение. В самой библиотеке SQLite по умолчанию ожидания нет, и если программа его не задала, ошибка появляется сразу. В sqlite3 ожидание задаёт команда .timeout 10000.
Режим WAL. В обычном режиме запись мешает чтению: пока изменения переносятся в файл базы, читать её нельзя. В режиме WAL читатели не мешают писателю, а писатель — читателям:
PRAGMA journal_mode = WAL;Команда отвечает wal, и режим запоминается в самом файле базы — повторять её при каждом подключении не нужно. Писать по-прежнему может только одно подключение за раз, но ошибок становится намного меньше. Рядом с базой появятся файлы -wal и -shm — это нормально, копируйте базу командой .backup (Резервная копия).
Когда SQLite мало
Если в базу постоянно пишут десятки программ или пользователей одновременно, SQLite будет упираться в одну запись за раз. Для такой нагрузки делают серверные СУБД — MySQL, MariaDB, PostgreSQL: они блокируют отдельные строки, а не всю базу. Подробнее о транзакциях — урок Транзакции.