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

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

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

  • 0
    Может быть другой процесс, который обращается к файлу базы данных - вы проверяли lsof?
  • 0
    У меня была та же проблема, проблема была в антивирусе, когда я деактивировал его, мое приложение работало хорошо, но когда я активировал его, я обнаружил некоторую ошибку "база данных заблокирована", я надеюсь, что это поможет вам.
Теги:

37 ответов

227
Лучший ответ

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

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

$fuser development.db

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

> development.db: 5430

Просто запустите процесс...

kill -9 5430

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

  • 15
    ... с очевидным предостережением, что вам нужно знать, что вы делаете. Если это неважный процесс, тогда kill должен быть в порядке, но вы должны быть осторожны, чтобы уничтожить его правильно, и kill -9 , вероятно, неправильно и / или перебор. Если процесс завис и не умрет, иногда вам нужно kill -9 . Но вы не хотите убивать основную производственную работу, просто чтобы сообщить, что база данных больше не заблокирована!
  • 0
    Более простым решением было бы просто перезагрузить компьютер.
Показать ещё 10 комментариев
82

Я заставил sqlite db стать заблокированным, разбив приложение во время записи. Вот как я его исправил:

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

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

  • 3
    это не решение, но достаточно хороший обходной путь
  • 2
    sqlite3: sqlite> .dump PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; /**** ERROR: (5) database is locked *****/ ROLLBACK; -- due to errors
Показать ещё 1 комментарий
51

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

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

  • 1
    Проблема в том, что страница либо неверна, либо устарела: у меня есть процесс, который буквально ничего не делает, кроме одной вставки, которая получает заблокированное сообщение: этот процесс не может вызвать блокировку. Проблема была в другом процессе, говорящем с той же БД.
  • 0
    Я единственный, кто получает сообщение об ошибке на этой странице? В нем говорится об Database Error db_execute: Database execute failed REPLACE INTO access_load(ipaddr,load,lastaccess,captcha) VALUES('xxx.xxx.xxx.xxx',1,1472597572,5) Reason: attempt to write a readonly database не знаю, меня троллируют?
Показать ещё 1 комментарий
27

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

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

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

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

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

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

12

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

  • Скопируйте файл базы данных в другое место.
  • Замените базу данных скопированной базой данных. Это приведет к разыменованию всех процессов, которые обращаются к вашему файлу базы данных.
  • 1
    Я попытался «fuser <DB>», как описано выше, но не сработало. Эти простые шаги работают на меня.
  • 0
    Интересный шаг разыменования, спасибо!
12

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

  • 38
    так как разблокировать дб?
  • 3
    Это просто неправда. Блокировки поддерживаются ОС. Прочитайте ответ ниже.
10

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

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

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

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

4

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

  • 0
    Спасибо! У меня была та же проблема, и я всегда думал, что DbCommand не был утилизирован !!
4

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

4

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

3

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

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

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

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

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

3

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

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

sqlite_reset(xxx);

или

sqlite_finalize(xxx);
3

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

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

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

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

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

2
Команда

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

2

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

  • Обеспечить экспорт ваших таблиц (вы можете использовать "менеджер SQLite" в Firefox)
  • Если миграция изменит вашу схему базы данных, удалите последнюю неудачную миграцию.
  • Переименуйте файл "database.sqlite"
  • Выполнить "rake db: migrate", чтобы создать новую рабочую базу данных
  • Предоставить права доступа к базе данных для импорта таблиц
  • Импорт резервных таблиц
  • Напишите новую миграцию
  • Выполните его с помощью < rake db:migrate "
  • 0
    Именно то, о чем я думал, но потом я подумал, что должен сначала проверить все ответы, чтобы увидеть, сказал ли кто-то еще «просто сбрось это и скопируй». :-)
2

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

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

  • 0
    +1 при перезапуске Apache решил проблему за меня. Если сценарий PHP умер, когда было открыто соединение SQLite, возможно, это было причиной.
2

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

1

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

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

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

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

И это тоже:

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

После обработки космической ситуации все вернулось к нормальному состоянию.

1

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

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

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

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

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

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

1

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

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

мой код 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 )
1

У меня была такая же ошибка. После 5 митингов google-ing я обнаружил, что я не закрыл одну оболочку, использующую db. Просто закройте его и повторите попытку;)

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

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

0

Я также получал блокировки sqlite в приложении С#.NET 4.6.1, которое я создал, когда оно пыталось записать данные, но не при запуске приложения в Visual Studio на моем компьютере разработчика. Вместо этого это происходило только тогда, когда приложение было установлено и запущено на удаленной машине с Windows 10.

Первоначально я думал, что это были разрешения файловой системы, однако оказалось, что драйверы пакетов System.Data.SQLite(v1.0.109.2), которые я установил в проекте с помощью Nuget, вызывали проблему. Я удалил пакет NuGet и вручную сослался на более старую версию драйверов в проекте, и после переустановки приложения на удаленном компьютере проблемы с блокировкой волшебным образом исчезли. Можно только думать, что произошла ошибка с последними драйверами или пакетом Nuget.

0

Если вы пытаетесь разблокировать базу данных 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

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

Итак, остановите этот процесс, который использует конкретную базу данных, а затем выполните ваш запрос.

0

В моем случае я также получил эту ошибку.

Я уже проверял другие процессы, которые могут быть причиной заблокированной базы данных, такой как (SQLite Manager, другие программы, которые подключаются к моей базе данных). Но нет другой программы, которая соединяется с ней, это просто еще один активный SQLConnection в том же приложении, который остается подключен.

Попробуйте проверить предыдущий активный активный SQLConnection, который может быть все еще подключен (сначала отключите его), прежде чем устанавливать новую команду SQLConnection и .

0

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

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

0

Adminer - небольшая (но мощная) альтернатива phpmyadmin, которую я использую для мониторинга базы данных sqlite. По какой-то причине база данных была заблокирована. Вот как я его исправил.

  • Я загрузил файл sqlite в свою систему (FTP)
  • Удаленный онлайн файл sqlite
  • Загрузили файл обратно хостинг-провайдеру

Теперь он отлично работает.

0

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

0

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

0

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

Похоже, когда вы добавляете; sqlite'll будет искать дополнительную команду.

0

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

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

0

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

Это может означать, что вы открыли транзакцию (EXCLUSIVE?) и еще не зафиксировали данные. Ваша программа или какой-либо другой процесс оставил -journal позади?

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню