Python SQLite: база данных заблокирована

Я пытаюсь этот код:

import sqlite

connection = sqlite.connect('cache.db')
cur = connection.cursor()
cur.execute('''create table item
  (id integer primary key, itemno text unique,
        scancode text, descr text, price real)''')

connection.commit()
cur.close()

Я ловлю это исключение:

Traceback (most recent call last):
  File "cache_storage.py", line 7, in <module>
    scancode text, descr text, price real)''')
  File "/usr/lib/python2.6/dist-packages/sqlite/main.py", line 237, in execute
    self.con._begin()
  File "/usr/lib/python2.6/dist-packages/sqlite/main.py", line 503, in _begin
    self.db.execute("BEGIN")
_sqlite.OperationalError: database is locked

Разрешения для cache.db в порядке. Есть идеи?

23 ответа

Решение

Оказалось, что проблема произошла, потому что путь к файлу d b был на самом деле смонтированным каталогом samba. Я переместил это, и это начало работать.

Я предполагаю, что вы на самом деле используете sqlite3, хотя ваш код говорит иначе. Вот несколько вещей для проверки:

  1. Что у вас нет зависшего процесса в файле (unix: $ fuser cache.db нечего сказать)
  2. В каталоге с cache.db нет файла cache.db-journal; это будет указывать на сбойный сеанс, который не был очищен должным образом.
  3. Попросите оболочку базы данных проверить себя: $ sqlite3 cache.db "pragma integrity_check;"
  4. Резервное копирование базы данных $ sqlite3 cache.db ".backup cache.db.bak"
  5. Удалите cache.db, так как в нем, вероятно, ничего нет (если вы только учитесь), и попробуйте снова свой код
  6. Посмотрите, работает ли резервная копия $ sqlite3 cache.db.bak ".schema"

В противном случае прочитайте, что может пойти не так, и как повредить файлы базы данных.

Установите параметр времени ожидания в вашем соединении, как в:

connection = sqlite.connect('cache.db', timeout=10)

Я знаю, что это старый, но я все еще получаю проблему, и это первая ссылка на Google для этого. ОП сказал, что его проблема заключалась в том, что.db сидел на SMB-ресурсе, что было именно моей ситуацией. Мои десять минут исследования показывают, что это известный конфликт между sqlite3 и smb; Я нашел сообщения об ошибках, начиная с 2007 года.

Я решил это, добавив опцию "nobrl" к моей строке монтирования smb в / etc / fstab, так что теперь эта строка выглядит так:

//SERVER/share /mnt/point cifs credentials=/path/to/.creds,sec=ntlm,nobrl 0 0

Эта опция не позволяет вашему SMB-клиенту отправлять блокировки диапазона байтов на сервер. Я не слишком разбираюсь в деталях своего протокола SMB, но я лучше всего могу сказать, что этот параметр будет в основном интересен в многопользовательской среде, где кто-то другой может пытаться записать в тот же самый БД, что и вы. По крайней мере, для домашней установки это достаточно безопасно.

Мои соответствующие версии:

  • Монетный двор 17.1 Ребекка
  • SMB v4.1.6-Ubuntu
  • Python v3.4.0
  • SQLite v3.8.2
  • Сетевой ресурс размещен на сервере Win12R2

Причина, по которой мое сообщение показывало сообщение "Блокировка", на самом деле была связана с тем, что я открыл IDE SQLite3 на моем Mac, и именно по этой причине оно было заблокировано. Я предполагаю, что я играл с БД в IDE и не сохранил изменения, и поэтому была установлена ​​блокировка.

Короче говоря, убедитесь, что на БД нет несохраненных изменений, а также что он не используется в других местах.

В Linux вы можете сделать нечто подобное, например, если ваш заблокированный файл - development.db:

$ fuser development.db Эта команда покажет, какой процесс блокирует файл:

development.db: 5430 Просто убей процесс...

kill -9 5430... И ваша база данных будет разблокирована.

Поскольку эта проблема по-прежнему остается самой популярной в Google, позвольте мне добавить возможную причину. Если вы редактируете структуру своей базы данных и не зафиксировали изменения, база данных блокируется до тех пор, пока вы не подтвердите или не отмените ее.

(Вероятно, необычно, но я разрабатываю приложение, поэтому код и база данных разрабатываются одновременно)

Вот удобный обходной путь для одновременного доступа:

while True:
    connection = sqlite3.connect('user.db', timeout=1)
    cursor = connection.cursor()
    try:
        cursor.execute("SELECT * FROM queue;")
        result = cursor.fetchall()
    except sqlite3.OperationalError:
        print("database locked")
    num_users = len(result)
# ...

База данных заблокирована другим процессом, который пишет в нее. Вы должны подождать, пока другая транзакция не будет совершена. Смотрите документацию по connect()

Вам следует проверить, не работает ли в вашей базе данных платформа администрирования и разработки СУБД (например, pgAdmin), так как это, вероятно, самая распространенная причина этой ошибки. Если есть - зафиксируйте внесенные изменения и проблема исчезнет.

  1. Ваш cache.db в настоящее время используется другим процессом.
  2. Остановите этот процесс и попробуйте снова, он должен работать.

Одной из возможных причин блокировки базы данных, с которой я столкнулся с SQLite, является то, что я пытался получить доступ к строке, которая была написана одним приложением и одновременно прочитана другим. Возможно, вы захотите установить время ожидания занятости в вашей оболочке SQLite, которое будет вращаться и ожидать освобождения базы данных (в исходном API- интерфейсе C++ функция sqlite3_busy_timeout). Я обнаружил, что 300 мс было достаточно в большинстве случаев.

Но я сомневаюсь, что это проблема, основанная на вашем посте. Попробуйте сначала другие рекомендации.

Еще одна возможность, которая произошла со мной, я дважды открывал базу данных, первое открытие заблокировало второе. Проверьте, что вы не делаете этого.

У меня такая же проблема: sqlite3.IntegrityError

Как упоминалось во многих ответах, проблема в том, что соединение не было правильно закрыто.

В моем случае я имел tryexcept блоки. Я обращался к базе данных в try блок и когда возникло исключение, я хотел сделать что-то еще в except блок.

try:
    conn = sqlite3.connect(path)
    cur = conn.cursor()
    cur.execute('''INSERT INTO ...''')
except:
    conn = sqlite3.connect(path)
    cur = conn.cursor()
    cur.execute('''DELETE FROM ...''')
    cur.execute('''INSERT INTO ...''')

Однако, когда возникло исключение, соединение от try Блок не был закрыт.

Я решил это используя with заявления внутри блоков.

try:
    with sqlite3.connect(path) as conn:
        cur = conn.cursor()
        cur.execute('''INSERT INTO ...''')
except:
    with sqlite3.connect(path) as conn:
        cur = conn.cursor()
        cur.execute('''DELETE FROM ...''')
        cur.execute('''INSERT INTO ...''')

в моем случае сообщение 'заблокировано' произошло из-за несохраненных изменений, которые я сделал в DB BROWSER(SQL LITE), мне пришлось сохранить их, а затем, когда я снова выполнил свой скрипт, проблема была решена, надеюсь, это поможет кому-то как в моем случае.

У меня была эта проблема при работе с Pycharm и с базой данных, которая была первоначально предоставлена ​​мне другим пользователем.

Итак, вот как я решаю это в моем случае:

  1. Закрыты все вкладки в Pycharm, которые работают с проблемной базой данных.
  2. Остановите все запущенные процессы из нижней части красного квадрата в верхнем правом углу Pycharm.
  3. Удалить проблемную базу данных из каталога.
  4. Загрузите снова исходную базу данных. И это снова сработало.

О, ваш откат дал это: у вас конфликт версий. Вы установили некоторую старую версию sqlite в локальный каталог dist-packages, когда у вас уже есть sqlite3, включенный в ваш дистрибутив python2.6, и вам не требуется и, вероятно, вы не можете использовать старую версию sqlite. Первая попытка:

$ python -c "import sqlite3"

и если это не приводит к ошибке, удалите ваш dist-пакет:

easy_install -mxN sqlite

а потом import sqlite3 в своем коде вместо этого и получайте удовольствие.

В моем случае ошибка произошла, когда много одновременных процессов пытались читать / писать в одну и ту же таблицу. Я использовал повтор, чтобы обойти проблему

def _retry_if_exception(exception):
    return isinstance(exception, Exception)

@retry(retry_on_exception=_retry_if_exception,
       wait_random_min=1000,
       wait_random_max=5000,
       stop_max_attempt_number=5)
def execute(cmd, commit=True):
   c.execute(cmd)
   c.conn.commit()

У меня тоже была эта проблема. Я пытался ввести данные в базу данных без сохранения внесенных в нее изменений. после того как я сохранил изменения работали

Простое решение: проверьте один раз, открыли ли вы базу данных в другом окне или в другом терминале. Это также блокирует вашу базу данных. В моем случае я закрыл все остальные терминалы, которые блокировали базу данных (вкладка терминала в Pycharm). Также проверьте каждую вкладку терминалов вашей IDE, если есть терминал, который оставил базу данных открытой. exit() все терминалы должны работать, разблокируя базу данных.

Я использую sqlite3, я решаю проблему блокировки, добавляя уровень изоляции транзакций conn= sqlite3.connect('image.db',isolation_level=None,timeout=0.01);

Даже когда у меня был только один писатель и один читатель, моя проблема заключалась в том, что одно из чтений занимало слишком много времени: дольше, чем предусмотренный тайм-аут в 5 секунд. Таким образом, время записи истекло и возникла ошибка.

Поэтому будьте осторожны при чтении всех записей из базы данных, особенно из той, размер таблицы которой со временем увеличивается.

Я обнаружил, что это сработало для моих нужд. (блокировка резьбы) YMMV

conn = sqlite3.connect(база данных, тайм-аут =10)

https://docs.python.org/3/library/sqlite3.html

sqlite3.connect(база данных [, тайм-аут, обнаружение_типов, уровень_изоляции, имя_проверки_потока, фабрика, cached_statements, uri])

Когда к базе данных обращается несколько подключений и один из процессов изменяет базу данных, база данных SQLite блокируется до тех пор, пока транзакция не будет зафиксирована. Параметр тайм-аута указывает, как долго соединение должно ждать снятия блокировки до возникновения исключения. По умолчанию для параметра тайм-аута установлено значение 5,0 (пять секунд).

Другие вопросы по тегам