Глиф Учебники

Ошибка database is locked в SQLite

Справочник · SQL · 2 минуты чтения

SQLite пишет database is locked, когда другое подключение держит открытую транзакцию с изменениями. В SQLite писать в базу может только одно подключение за раз, остальные ждут. Если ждать пришлось дольше заданного времени — эта ошибка. Решение — найти, кто держит базу, и завершить его транзакцию.

Кто держит базу

Чаще всего это одно из:

В Linux программы, у которых открыт файл, показывает команда lsof shop.db (или fuser shop.db).

Не удаляйте файлы shop.db-journal и shop.db-wal рядом с базой, чтобы «снять блокировку». В них лежат данные незавершённой или ещё не перенесённой в базу транзакции. Без них база может оказаться испорченной или потерять последние изменения. Блокировку снимает только завершение транзакции или закрытие программы.

Как избежать

Короткие транзакции. Открыли, изменили, зафиксировали — сразу. Не держите транзакцию, пока программа ждёт ввода, скачивает файл или делает долгие расчёты. В Python удобно так:

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 то же задаёт команда:

SQL
PRAGMA busy_timeout = 10000;

Значение — в миллисекундах, действует на текущее подключение. В самой библиотеке SQLite по умолчанию ожидания нет, и если программа его не задала, ошибка появляется сразу. В sqlite3 ожидание задаёт команда .timeout 10000.

Режим WAL. В обычном режиме запись мешает чтению: пока изменения переносятся в файл базы, читать её нельзя. В режиме WAL читатели не мешают писателю, а писатель — читателям:

SQL
PRAGMA journal_mode = WAL;

Команда отвечает wal, и режим запоминается в самом файле базы — повторять её при каждом подключении не нужно. Писать по-прежнему может только одно подключение за раз, но ошибок становится намного меньше. Рядом с базой появятся файлы -wal и -shm — это нормально, копируйте базу командой .backup (Резервная копия).

Когда SQLite мало

Если в базу постоянно пишут десятки программ или пользователей одновременно, SQLite будет упираться в одну запись за раз. Для такой нагрузки делают серверные СУБД — MySQL, MariaDB, PostgreSQL: они блокируют отдельные строки, а не всю базу. Подробнее о транзакциях — урок Транзакции.