Как мне разблокировать базу данных SQLite?

StackOverflow https://stackoverflow.com/questions/151026

  •  02-07-2019
  •  | 
  •  

Вопрос

sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked

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

Это было полезно?

Решение

В Windows вы можете попробовать эту программу http://www.nirsoft.net/utils/opened_files_view.html чтобы выяснить, что это за процесс обработки файла базы данных.Попробуйте закрыть эту программу для разблокировки базы данных

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

$ разработка термоблока.db

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

> development.db:5430

Просто остановите процесс...

убийство -9 5430

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

Другие советы

Я привел к блокировке моей базы данных sqlite из-за сбоя приложения во время записи.Вот как я это исправил:

echo ".dump" | sqlite old.db | sqlite new.db

Взято из: http://random.kakaopor.hu/how-to-repair-an-sqlite-database

Страница с блокировкой базы данных, указанная ниже, больше недоступна.Страница Блокировка файлов и параллелизм описывает изменения, связанные с блокировкой файлов, введенные в версии v3, и могут быть полезны будущим читателям. https://www.sqlite.org/lockingv3.html

Вики - сайт SQLite Заблокированная база данных страница предлагает хорошее объяснение этого сообщения об ошибке.В нем, в частности, говорится, что источник конфликта является внутренним (для процесса, выдающего ошибку).

Чего на этой странице не объясняется, так это того, как SQLite решает, что что-то в вашем процессе содержит блокировку, и какие условия могут привести к ложноположительному результату.

Удаление файла -journal звучит как ужасная идея.Он предназначен для того, чтобы позволить sqlite откатить базу данных до согласованного состояния после сбоя.Если вы удалите его, пока база данных находится в несогласованном состоянии, вы останетесь с поврежденной базой данных.Цитируя страницу из сайт sqlite:

Если происходит сбой или отключение питания, и на диске остается "горячий журнал", важно, чтобы исходный файл базы данных и "горячий журнал" оставались на диске с их первоначальными именами до тех пор, пока файл базы данных не будет открыт другим процессом SQLite и выполнен откат.[...]

Мы подозреваем, что обычный режим сбоя для восстановления SQLite происходит следующим образом:Происходит сбой питания.После восстановления питания благонамеренный пользователь или системный администратор начинает осматривать диск в поисках повреждений.Они видят файл своей базы данных с именем "important.data".Возможно, этот файл им знаком.Но после сбоя появляется также горячий журнал под названием "important.data-journal".Затем пользователь удаляет горячий журнал, думая, что он помогает очистить систему.Мы не знаем другого способа предотвратить это, кроме обучения пользователей.

Предполагается, что откат произойдет автоматически при следующем открытии базы данных, но произойдет сбой, если процесс не сможет заблокировать базу данных.Как уже говорили другие, одной из возможных причин этого является то, что в настоящее время он открыт для другого процесса.Другой возможностью является устаревшая блокировка NFS, если база данных находится на томе NFS.В этом случае обходным путем является замена файла базы данных новой копией, которая не заблокирована на сервере NFS (mv database.db original.db;cp original.db база данных.db).Обратите внимание, что часто задаваемые вопросы по sqlite рекомендуют соблюдать осторожность в отношении одновременного доступа к базам данных на томах NFS из-за ошибочных реализаций блокировки файлов NFS.

Я не могу объяснить, почему удаление файла a -journal позволит вам заблокировать базу данных, чего вы не могли раньше.Это воспроизводимо?

Кстати, наличие файла -journal не обязательно означает, что произошел сбой или что есть изменения, которые необходимо откатить.В Sqlite есть несколько различных режимов ведения журнала, и в режимах СОХРАНЕНИЯ или УСЕЧЕНИЯ он всегда оставляет файл -journal на месте и изменяет содержимое, чтобы указать, есть ли частичные транзакции для отката.

Если вы хотите удалить ошибку "база данных заблокирована", выполните следующие действия:

  1. Скопируйте файл вашей базы данных в какое-нибудь другое место.
  2. Замените базу данных скопированной базой данных.Это приведет к разыменованию всех процессов, которые обращались к вашему файлу базы данных.

Если процесс заблокировал базу данных SQLite и произошел сбой, база данных остается заблокированной навсегда.В этом-то и проблема.Дело не в том, что какой-то другой процесс имеет блокировку.

файлы базы данных SQLite - это просто файлы, поэтому первым шагом было бы убедиться, что они не доступны только для чтения.Другое, что нужно сделать, это убедиться, что у вас нет какого-либо средства просмотра базы данных SQLite с графическим интерфейсом с открытой базой данных.Вы могли бы открыть базу данных в другой оболочке, или в вашем коде база данных может быть открыта.Обычно вы бы увидели это, если бы другой поток или приложение, такое как браузер базы данных SQLite, открыли базу данных для записи.

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

Предложенные выше рецепты восстановления у меня не сработали (включая идею сначала переместить, а затем скопировать базу данных обратно).Но после копирования ее в систему, отличную от NFS, база данных стала пригодной для использования, и, похоже, данные не были потеряны.

Моя блокировка была вызвана сбоем системы, а не зависшим процессом.Чтобы решить эту проблему, я просто переименовал файл, а затем скопировал его обратно к его первоначальному имени и местоположению.

Используя оболочку Linux, которая была бы...

mv mydata.db temp.db
cp temp.db mydata.db

Я добавил "Pooling=true"к строке подключения, и это сработало.

Я нашел тот самый Документация из различных состояний блокировки в SQLite, чтобы быть очень полезным.Майкл, если вы можете выполнять чтение, но не можете выполнять запись в базу данных, это означает, что процесс получил ЗАРЕЗЕРВИРОВАННУЮ блокировку вашей базы данных, но еще не выполнил запись.Если вы используете SQLite3, существует новая блокировка под названием PENDING, при которой больше процессам не разрешено подключаться, но существующие соединения могут выполнять операции чтения, поэтому, если это проблема, вам следует вместо этого взглянуть на это.

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

У меня есть такая проблема в приложении, которое получает доступ к SQLite из 2 подключений - одно было доступно только для чтения, а второе - для записи и чтения.Похоже, что это соединение только для чтения заблокировало запись со второго соединения.Наконец, выясняется, что требуется доработать или, по крайней мере, сбросить подготовленные инструкции СРАЗУ после использования.До тех пор, пока подготовленная инструкция не будет открыта, это приводило к тому, что база данных блокировалась для записи.

НЕ ЗАБУДЬ ПОЗВОНИТЬ:

sqlite_reset(xxx);

или

sqlite_finalize(xxx);

Некоторые функции, такие как ИНДЕКСИРОВАНИЕ, могут занимать очень много времени - и это блокирует всю базу данных во время ее выполнения.В подобных случаях он может даже не использовать файл журнала!

Таким образом, лучший / единственный способ проверить, заблокирована ли ваша база данных из-за того, что процесс АКТИВНО записывает в нее данные (и, следовательно, вы должны оставить его в покое, пока он не завершит свою работу), - это ввести файл md5 (или md5sum в некоторых системах) дважды.Если вы получаете другую контрольную сумму, база данных записывается, и вы действительно действительно не хотите останавливать -9 этот процесс, потому что вы можете легко получить поврежденную таблицу / базу данных, если вы это сделаете.

Я повторю, потому что это важно - решение СОСТОИТ НЕ в том, чтобы найти блокирующую программу и уничтожить ее, а в том, чтобы выяснить, есть ли в базе данных блокировка записи по уважительной причине, и перейти оттуда.Иногда правильным решением является просто перерыв на кофе.

Единственный способ создать эту ситуацию с блокировкой, но не записываемую, - это запустить вашу программу BEGIN EXCLUSIVE, поскольку он хотел внести некоторые изменения в таблицу или что-то в этом роде, то по какой-либо причине никогда не отправляет END после этого, и этот процесс никогда не заканчивается.Выполнение всех трех условий крайне маловероятно в любом правильно написанном коде, и поэтому в 99 случаях из 100, когда кто-то хочет прервать -9 свой процесс блокировки, процесс блокировки фактически блокирует вашу базу данных по уважительной причине.Программисты обычно не добавляют BEGIN EXCLUSIVE условие, если только им это действительно не нужно, потому что это предотвращает параллелизм и увеличивает количество жалоб пользователей.Сам SQLite добавляет его только тогда, когда это действительно необходимо (например, при индексации).

Наконец, статус "заблокирован" не существует ВНУТРИ файла, как указано в нескольких ответах - он находится в ядре операционной системы.Процесс, который был запущен BEGIN EXCLUSIVE запросил у операционной системы наложение блокировки на файл.Даже если ваш эксклюзивный процесс потерпел крах, ваша операционная система сможет определить, должна ли она поддерживать блокировку файлов или нет!!Невозможно получить базу данных, которая заблокирована, но ни один процесс не блокирует ее активно!!Когда дело доходит до определения того, какой процесс блокирует файл, обычно лучше использовать lsof, а не fuser (это хорошая демонстрация того, почему: https://unix.stackexchange.com/questions/94316/fuser-vs-lsof-to-check-files-in-use).В качестве альтернативы, если у вас есть DTrace (OSX), вы можете использовать iosnoop для файла.

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

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

lsof команда в моей среде Linux помогла мне понять, что процесс зависает, сохраняя файл открытым.
Остановил процесс, и проблема была решена.

Эта ссылка решит проблему.: Когда Sqlite выдает :Ошибка блокировки базы данных Это решило мою проблему и может быть вам полезно.

И вы можете использовать begin transaction и end transaction, чтобы не блокировать базу данных в будущем.

Это должна быть внутренняя проблема базы данных...
Для меня это проявилось после попытки просмотреть базу данных с помощью "SQLite manager"...
Итак, если вы не можете найти другой процесс, подключающийся к базе данных, и вы просто не можете это исправить, просто попробуйте это радикальное решение:

  1. Предоставьте возможность экспорта ваших таблиц (вы можете использовать "SQLite manager" в Firefox).
  2. Если миграция изменит схему вашей базы данных, удалите последнюю неудачную миграцию
  3. Переименуйте ваш файл "database.sqlite"
  4. Выполните команду "rake db: migrate", чтобы создать новую рабочую базу данных
  5. Предоставьте, чтобы предоставить правильные разрешения базе данных для импорта таблицы
  6. Импортируйте ваши резервные копии таблиц
  7. Напишите новую миграцию
  8. Выполните это с помощью "rake db:migrate"

Я столкнулся с такой же проблемой в Mac OS X 10.5.7, запуская скрипты Python из терминального сеанса.Несмотря на то, что я остановил скрипты и окно терминала находилось в командной строке, оно выдаст эту ошибку при следующем запуске.Решение состояло в том, чтобы закрыть окно терминала, а затем открыть его снова.Для меня это не имеет смысла, но это сработало.

У меня только что была такая же ошибка.Через 5 минут поиска в Google я обнаружил, что не закрыл ни одну оболочку, которая использовала БД.Просто закройте его и попробуйте еще раз ;)

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

Надеюсь, это поможет

мой код на Python

##############
#### Defs ####
##############
def conn_exec( connection , cursor , cmd_str ):
    done        = False
    try_count   = 0.0
    while not done:
        try:
            cursor.execute( cmd_str )
            done = True
        except sqlite.IntegrityError:
            # Ignore this error because it means the item already exists in the database
            done = True
        except Exception, error:
            if try_count%60.0 == 0.0:       # print error every minute
                print "\t" , "Error executing command" , cmd_str
                print "Message:" , error

            if try_count%120.0 == 0.0:      # if waited for 2 miutes, roll back
                print "Forcing Unlock"
                connection.rollback()

            time.sleep(0.05)    
            try_count += 0.05


def conn_comit( connection ):
    done        = False
    try_count   = 0.0
    while not done:
        try:
            connection.commit()
            done = True
        except sqlite.IntegrityError:
            # Ignore this error because it means the item already exists in the database
            done = True
        except Exception, error:
            if try_count%60.0 == 0.0:       # print error every minute
                print "\t" , "Error executing command" , cmd_str
                print "Message:" , error

            if try_count%120.0 == 0.0:      # if waited for 2 miutes, roll back
                print "Forcing Unlock"
                connection.rollback()

            time.sleep(0.05)    
            try_count += 0.05       




##################
#### Run Code ####
##################
connection = sqlite.connect( db_path )
cursor = connection.cursor()
# Create tables if database does not exist
conn_exec( connection , cursor , '''CREATE TABLE IF NOT EXISTS fix (path TEXT PRIMARY KEY);''')
conn_exec( connection , cursor , '''CREATE TABLE IF NOT EXISTS tx (path TEXT PRIMARY KEY);''')
conn_exec( connection , cursor , '''CREATE TABLE IF NOT EXISTS completed (fix DATE, tx DATE);''')
conn_comit( connection )

Одной из распространенных причин получения этого исключения является то, что вы пытаетесь выполнить операцию записи, все еще удерживая ресурсы для операции чтения.Например, если вы ВЫБИРАЕТЕ из таблицы, а затем пытаетесь ОБНОВИТЬ что-то, что вы выбрали, не закрывая сначала свой результирующий набор.

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

В Linux можно использовать fuser с этой целью:

$ fuser database.db

$ fuser database.db-journal

В моем случае я получил следующий ответ:

philip    3556  4700  0 10:24 pts/3    00:00:01 /usr/bin/python manage.py shell

Который показал, что у меня была другая программа на Python с pid 3556 (manage.py), использующая базу данных.

Старый вопрос с большим количеством ответов, вот шаги, которым я недавно следовал, читая ответы выше, но в моем случае проблема была связана с общим использованием ресурсов cifs.Об этом случае ранее не сообщалось, так что надеюсь, это кому-то поможет.

  • Убедитесь, что в вашем java-коде не осталось открытых подключений.
  • Убедитесь, что никакие другие процессы не используют ваш файл базы данных SQLite с помощью lsof.
  • Убедитесь, что пользователь-владелец вашего запущенного процесса jvm имеет права доступа к файлу.
  • Попробуйте принудительно включить режим блокировки при открытии соединения с помощью

    final SQLiteConfig config = new SQLiteConfig();
    
    config.setReadOnly(false);
    
    config.setLockingMode(LockingMode.NORMAL);
    
    connection = DriverManager.getConnection(url, config.toProperties());
    

Если вы используете файл базы данных SQLite поверх общей папки NFS, проверьте этот момент из часто задаваемых вопросов по SQLite и просмотрите параметры конфигурации монтирования, чтобы убедиться, что вы избегаете блокировок, как описано здесь:

//myserver /mymount cifs username=*****,password=*****,iocharset=utf8,sec=ntlm,file,nolock,file_mode=0700,dir_mode=0700,uid=0500,gid=0500 0 0

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

База данных SQLite базировалась в файловой системе NFS, совместно используемой тремя серверами.На 2 серверах я смог успешно выполнить запросы к базе данных, на третьем мне показалось, что я получаю сообщение "база данных заблокирована".

Проблема с этой 3-й машиной заключалась в том, что на ней не осталось свободного места /var.Каждый раз, когда я пытался запустить запрос в ЛЮБОЙ базе данных SQLite, расположенной в этой файловой системе, я получал сообщение "база данных заблокирована", а также эту ошибку в журналах:

8 Августа 10:33:38 ядро server01:запертый:не удается отследить 172.22.84.87

И этот тоже:

8 Августа 10:33:38 сервер01 rpc.statd[7430]:Не удалось вставить:запись /var/lib/nfs/statd/sm/other.server.name.com:На устройстве не осталось свободного места 8 августа 10:33:38 server01 rpc.statd[7430]:STAT_FAIL на server01 для SM_MON из 172.22.84.87

После того, как космическая ситуация была улажена, все вернулось в нормальное русло.

Из ваших предыдущих комментариев вы сказали, что файл a -journal присутствует.

Это может означать, что вы открыли (ЭКСКЛЮЗИВНУЮ?) транзакцию и еще не зафиксировали данные.Оставила ли ваша программа или какой-либо другой процесс -journal позади??

Перезапуск процесса sqlite просмотрит файл журнала, очистит все незафиксированные действия и удалит файл -journal.

Как сказал Сын Осева, иногда процесс-зомби будет находиться в терминале с установленной блокировкой, даже если вы не считаете это возможным.Ваш скрипт запускается, завершается сбоем, и вы возвращаетесь к командной строке, но где-то есть зомби-процесс, порожденный вызовом библиотеки, и у этого процесса есть блокировка.

Закрытие терминала, в котором вы находились (в OSX), может сработать.Перезагрузка сработает.Вы могли бы найти процессы "python" (например), которые ничего не делают, и убить их.

вы можете попробовать это: .timeout 100 чтобы установить тайм - аут .Я не знаю, что происходит в командной строке, но в C #.Net, когда я делаю это: "UPDATE table-name SET column-name = value;" Я получаю, что база данных заблокирована, но это "UPDATE table-name SET column-name = value" все идет нормально.

Похоже, что когда вы добавите;, sqlite будет искать дальнейшую команду.

Я получил эту ошибку при использовании Delphi с компонентами LiteDAC.Оказалось, что это произошло только при запуске моего приложения из среды IDE Delphi, если для свойства Connected было установлено значение True для компонента SQLite connection (в данном случае TLiteConnection).

У меня также были ошибки "база данных заблокирована" в многопоточном приложении, которое, по-видимому, SQLITE_BUSY SQLITE_BUSY результирующий код, и я решил его с помощью настройки sqlite3_busy_timeout - время загрузки до чего-то подходящей длины, например, 30000.

(Кстати, как странно, что по вопросу 7-летней давности никто этого еще не выяснил!SQLite действительно своеобразный и удивительный проект ...)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top