Я сделал несколько повторяющихся операций в своем приложении (тестирование), и внезапно Im получил странную ошибку:
OperationalError: database is locked
Я перезапустил сервер, но ошибка сохраняется. О чем это может быть?
Я сделал несколько повторяющихся операций в своем приложении (тестирование), и внезапно Im получил странную ошибку:
OperationalError: database is locked
Я перезапустил сервер, но ошибка сохраняется. О чем это может быть?
Из django doc:
SQLite должен быть легким базы данных и, следовательно, не может поддерживать высокий уровень concurrency. Операционная защита: база данных заблокирована ошибки указывают, что ваше приложение испытывает больше concurrency, чем sqlite может обрабатывать по умолчанию конфигурации. Эта ошибка означает, что один поток или процесс имеет эксклюзивный блокировка соединения с базой данных и другой поток, ожидающий блокировка будет выпущена.
Оболочка Python SQLite имеет значение по умолчанию время ожидания, определяющее, как долго второй поток можно ждать на замке перед тем, как он истечет и повышает базу данных OperationalError: ошибка заблокирована.
Если вы получаете эту ошибку, вы можете решить его:
Переход на другой сервер базы данных. В какой-то момент SQLite становится слишком "lite" для реальных приложений, и эти типы ошибок concurrencyукажите, что вы достигли этой точки.
Переписывание кода для уменьшения concurrency и убедитесь, что база данных транзакции недолговечны.
Увеличьте значение таймаута по умолчанию на установка опции базы данных таймаута optionoption
http://docs.djangoproject.com/en/dev/ref/databases/#database-is-locked-errorsoption
Практическая причина этого часто заключается в том, что оболочки python или django открыли запрос в БД и не были закрыты должным образом; убийство вашего доступа к терминалу часто освобождает его. У меня была эта ошибка при запуске тестов командной строки.
Изменить: я получаю периодические upvotes на этом. Если вы хотите убить доступ без перезагрузки терминала, то из командной строки вы можете сделать:
from django import db
db.connections.close_all()
В моем случае это было потому, что я открываю базу данных из браузера SQLite. Когда я закрываю его из браузера, проблема исчезла.
Я не согласен с ответом @Patrick, который, цитируя этот документ, неявно связывает проблему OP (Database is locked
) с этим:
Переключение на другую базу данных. В определенный момент SQLite становится слишком "легким" для реальных приложений, и такого рода ошибки параллелизма указывают, что вы достигли этой точки.
Это немного "слишком просто", чтобы обвинить SQlite в этой проблеме. Если у вас не очень загруженный сервер с тысячами подключений в одну секунду, причиной этой ошибки Database is locked
, вероятно, является скорее неправильное использование API, чем проблема, свойственная SQlite, которая была бы "слишком легкой". Вот дополнительная информация о Пределах реализации для SQLite.
Теперь решение:
У меня была та же проблема, когда я использовал два сценария, использующих одну и ту же базу данных одновременно:
Решение: всегда выполняйте cursor.close()
как можно скорее после выполнения запроса (даже только для чтения).
Как уже говорили другие, есть другой процесс, который использует файл SQLite и не закрыл соединение. Если вы используете Linux, вы можете увидеть, какие процессы используют файл (например, db.sqlite3
), с помощью команды fuser
:
$ sudo fuser -v db.sqlite3
USER PID ACCESS COMMAND
/path/to/db.sqlite3:
user 955 F.... apache2
Если вы хотите остановить процессы, чтобы снять блокировку, используйте fuser -k
который отправляет сигнал KILL
всем процессам, обращающимся к файлу:
sudo fuser -k db.sqlite3
Обратите внимание, что это опасно, так как это может остановить процесс веб-сервера на рабочем сервере.
Спасибо @cz-game за указание на fuser
!
Для меня это решается, как только я закрыл оболочку django, которая была открыта с помощью python manage.py shell
Я столкнулся с этим сообщением об ошибке в ситуации, которая (явно) не указана в справочной информации, указанной в ответе Патрика.
Когда я использовал transaction.atomic()
, чтобы обернуть вызов в FooModel.objects.get_or_create()
, и вызывал этот код одновременно из двух разных потоков, только один поток завершился успешно, а другой получил ошибку "база данных заблокирована". Изменение параметра базы данных тайм-аута не повлияло на поведение.
Я думаю, это связано с тем, что sqlite не может обрабатывать несколько одновременных писателей, поэтому приложение должно сериализовать записи самостоятельно.
Я решил проблему, используя объект threading.RLock
вместо transaction.atomic()
, когда мое приложение Django работает с бэкэндом sqlite. Это не совсем эквивалентно, поэтому вам может потребоваться сделать что-то еще в вашем приложении.
Вот мой код, который запускает FooModel.objects.get_or_create
одновременно из двух разных потоков, в случае, если это полезно:
from concurrent.futures import ThreadPoolExecutor
import configurations
configurations.setup()
from django.db import transaction
from submissions.models import ExerciseCollectionSubmission
def makeSubmission(user_id):
try:
with transaction.atomic():
e, _ = ExerciseCollectionSubmission.objects.get_or_create(
student_id=user_id, exercise_collection_id=172)
except Exception as e:
return f'failed: {e}'
e.delete()
return 'success'
futures = []
with ThreadPoolExecutor(max_workers=2) as executor:
futures.append(executor.submit(makeSubmission, 296))
futures.append(executor.submit(makeSubmission, 297))
for future in futures:
print(future.result())
Это также может произойти, если вы подключены к своей базе данных sqlite через плагин dbbrowser через pycharm. Отключение решит проблему
У меня такая же ошибка! Одной из причин было закрытие соединения с БД. Поэтому проверьте наличие незакрытых соединений с БД. Кроме того, проверьте, если вы зафиксировали базу данных, прежде чем закрывать соединение.
В моем случае я не сохранил операцию базы данных, которую выполнял в браузере SQLite. Сохранение решило проблему.
ОБНОВЛЕНИЕ django версия 2.1.7
Я получил эту ошибку sqlite3.OperationalError: database is locked
с помощью pytest
с django
.
Решение:
Если мы используем @pytest.mark.django_db
декоратор. Что он делает, так это создает in-memory-db
для тестирования.
По имени: file:memorydb_default?mode=memory&cache=shared
Мы можем получить это имя с помощью:
from django.db import connection
db_path = connection.settings_dict['NAME']
Чтобы получить доступ к этой базе данных, а также отредактировать ее, выполните:
Подключиться к базе данных:
with sqlite3.connect(db_path, uri=True) as conn:
c = conn.cursor()
Используйте uri=True
чтобы указать файл диска, который является базой данных SQLite, которую нужно открыть.
Чтобы избежать ошибки, активируйте транзакции в декораторе:
@pytest.mark.django_db(transaction=True)
Финальная функция:
from django.db import connection
@pytest.mark.django_db(transaction=True)
def test_mytest():
db_path = connection.settings_dict['NAME']
with sqlite3.connect(db_path, uri=True) as conn:
c = conn.cursor()
c.execute('my amazing query')
conn.commit()
assert ... == ....
попробуйте выполнить эту команду:
sudo fuser -k 8000/tcp