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


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

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


Может быть другой процесс доступа к файлу базы данных - вы проверили lsof?
существует

У меня была та же проблема, проблема была в антивирусе, когда я деактивировал его, мое приложение работало хорошо, но когда я активировал его, я обнаружил некоторую ошибку "база данных заблокирована", я надеюсь, что это поможет вам.
user8510915

Ответы:


267

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

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

$ fuser development.db

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

> development.db: 5430

Просто убей процесс ...

убить -9 5430

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


19
... с очевидным предостережением, что вам нужно знать, что вы делаете. Если это неважный процесс, тогда все killбудет хорошо, но вы должны быть осторожны, чтобы убить его должным образом, и kill -9, вероятно, это неправильно и / или излишне. Если процесс завис и не умрет иначе, иногда вам это нужно kill -9. Но вы не хотите идти и убивать основное производственное задание, просто чтобы сообщить, что база данных больше не заблокирована!
tripleee

Более простым решением было бы просто перезагрузить компьютер.
chacham15

7
@ chacham15: вы предполагаете, что база данных находится на «моем» компьютере, и вы игнорируете возможность запуска множества важных процессов на том же компьютере, что и тот, на котором заблокирована база данных. «Более простое» решение никогда не бывает таким простым;)
tzot

1
@KyleCarlson - sqlite и mysql принципиально отличаются в этом аспекте. Нет ничего особенно плохого в SQLite-db-browser.
Ягода Цакала

6
Это решение предполагает, что существует процесс, блокирующий файл. Возможно, произошел сбой процесса, в результате чего файл SQLite оказался в непригодном для использования состоянии. В таком случае, смотрите мой ответ.
Роберт

90

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

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

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


4
sqlite3:sqlite> .dump PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; /**** ERROR: (5) database is locked *****/ ROLLBACK; -- due to errors
woky

Не работаетFOREIGN KEY constraint failed (RELEASE RESTOREPOINT)
gies0r

52

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

Страница SQLite wiki DatabaseIsLocked предлагает хорошее объяснение этого сообщения об ошибке. Отчасти утверждается, что источник разногласий является внутренним (для процесса, выдающего ошибку).

Эта страница не объясняет, как SQLite решает, что что-то в вашем процессе имеет блокировку, и какие условия могут привести к ложному срабатыванию.


2
Проблема в том, что страница либо неверна, либо устарела: у меня есть процесс, который буквально ничего не делает, кроме одного INSERT, который получает заблокированное сообщение: невозможно, чтобы этот процесс вызвал блокировку. Проблема была в другом процессе, говорящем с той же БД.
Дэн Джеймсон

4
@ converter42 Ссылка не работает.
Оле Танге

32

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

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

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

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

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

Кстати, наличие файла -journal не обязательно означает, что произошел сбой или есть изменения, которые необходимо откатить. Sqlite имеет несколько разных режимов ведения журнала, а в режимах PERSIST или TRUNCATE он всегда оставляет файл -journal на своем месте и изменяет его содержимое, чтобы указать, существуют ли частичные транзакции для отката.


23

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

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

2
Я попытался «fuser <DB>», как описано выше, но не сработало. Эти простые шаги работают на меня.
Джеки Йе

В моем случае мне также пришлось перезагрузить ноутбук Jupyter.
Виктор

15

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


48
так как разблокировать дб?
Эрик Каплун

4
Это просто неправда. Блокировки поддерживаются ОС. Прочитайте ответ ниже.
JJ

13

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


4
По моему опыту, SQLite Database Browser (SDB) воспроизводимо блокирует базу данных, если вы редактируете данные, но не сохраняете ее в SDB. Если вы сохраните его, он снимет блокировку.
Chelonian

Я могу вставить, но не могу удалить.
Венни

10

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

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


9

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

Использование оболочки Linux, которая была бы ...

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

очень простое решение, решение моей проблемы с заблокированной базой данных на сетевом диске.
Maverick2805


4

Я нашел документацию о различных состояниях блокировки в SQLite очень полезной. Майкл, если вы можете выполнять чтение, но не можете выполнять запись в базу данных, это означает, что процесс получил зарезервированную блокировку в вашей базе данных, но еще не выполнил запись. Если вы используете SQLite3, есть новая блокировка, называемая PENDING, в которой больше не разрешено подключать больше процессов, но существующие соединения могут выполнять чтение, поэтому, если это проблема, вы должны рассмотреть ее.


4

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


3

У меня есть такая проблема в приложении, что доступ к SQLite из 2-х подключений - одно только для чтения, а второе для записи и чтения. Похоже, что соединение только для чтения заблокировало запись со второго соединения. Наконец, оказывается, что необходимо завершить или, по крайней мере, сбросить подготовленные операторы НЕМЕДЛЕННО после использования. До тех пор, пока готовый оператор не будет открыт, он вызвал, что база данных была заблокирована для записи.

НЕ ЗАБЫВАЙТЕ ЗВОНИТЬ:

sqlite_reset(xxx);

или

sqlite_finalize(xxx);

3

Некоторые функции, такие как INDEX'ing, могут занимать очень много времени и блокировать всю базу данных во время работы. В таких случаях он может даже не использовать файл журнала!

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

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

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

Наконец, статус «заблокирован» не существует ВНУТРИ файла, как указано в нескольких ответах, - он находится в ядре операционной системы. Запущенный процесс BEGIN EXCLUSIVEзапросил у ОС блокировку файла. Даже если ваш эксклюзивный процесс потерпел крах, ваша ОС сможет выяснить, должна ли она поддерживать блокировку файла или нет !! Невозможно получить базу данных, которая заблокирована, но ни один процесс не блокирует ее активно !! Когда дело доходит до выяснения, какой процесс блокирует файл, обычно лучше использовать lsof, а не fuser (это хорошая демонстрация того, почему: /unix/94316/fuser-vs-lsof- проверять используемые файлы ). Кроме того, если у вас есть DTrace (OSX), вы можете использовать iosnoop для файла.


2

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

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


2

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



2

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

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

1

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


1

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


1

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

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

мой код на питоне

##############
#### 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 )

1

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


1

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

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


1

Прежде чем перейти к параметру перезагрузки, стоит посмотреть, сможете ли вы найти пользователя базы данных 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), использующая базу данных.


1

Старый вопрос с множеством ответов, вот шаги, которые я недавно выполнил, прочитав ответы выше, но в моем случае проблема была из-за совместного использования ресурсов 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

1

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

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

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

8 августа 10:33:38 server01 kernel: lockd: не может контролировать 172.22.84.87

И этот тоже:

8 августа 10:33:38 server01 rpc.statd [7430]: Не удалось вставить: writing /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

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


1

Если вы пытаетесь разблокировать базу данных Chrome, чтобы просмотреть ее с помощью SQLite , просто выключите Chrome.

Windows

%userprofile%\Local Settings\Application Data\Google\Chrome\User Data\Default\Web Data

or

%userprofile%\Local Settings\Application Data\Google\Chrome\User Data\Default\Chrome Web Data

макинтош

~/Library/Application Support/Google/Chrome/Default/Web Data

0

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

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

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


0

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

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


0

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.