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

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

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

Ответ 1

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

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

$fuser development.db

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

> development.db: 5430

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

kill -9 5430

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

Ответ 2

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

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

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

Ответ 8

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

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

Ответ 9

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

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

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

Ответ 10

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

Ответ 11

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

Ответ 12

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

Ответ 13

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

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

sqlite_reset(xxx);

или

sqlite_finalize(xxx);

Ответ 14

Некоторые функции, такие как 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 в файле.

Ответ 15

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

Ответ 16

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

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

Ответ 17

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

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

Ответ 18

Команда

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

Ответ 19

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

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

Ответ 20

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

Ответ 21

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

Ответ 22

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

Ответ 23

У меня была та же проблема. Очевидно, функция отката, по-видимому, перезаписывает 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 )

Ответ 24

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

Ответ 25

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

Ответ 26

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

База данных 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

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

Ответ 27

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

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

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

Ответ 28

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

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

Ответ 29

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

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

Ответ 30

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