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

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

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

30 ответов


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

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

$ Термоблок развития.db

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

> развитие.дБ: 5430

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

убить -9 5430

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


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

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

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


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

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


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

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

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

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

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

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


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


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

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

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


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

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


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


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


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

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

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

у меня есть такая проблема в приложении, доступ к 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 в файле.


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


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

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


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


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

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


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

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

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


У меня была такая же ошибка. После 5 минетов google - ing я обнаружил, что я не закрыл одну ведьму оболочки, используя 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 )

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


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

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

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

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

Aug 8 10: 33: 38 server01 ядро: блокировка: невозможно контролировать 172.22.84.87

а также:

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

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


из ваших предыдущих комментариев Вы сказали, что файл-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).


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

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

теперь он работает нормально.