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


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

Як розблокувати базу даних, щоб це спрацювало?


Можливо, є інший процес доступу до файлу бази даних - ви перевіряли lsof?
неіснуючий

У мене була така ж проблема, проблема була в антивірусі, коли я її деактивував, моє додаток працює добре, але коли я його активую, я знаходжу якусь помилку "база даних заблокована", я сподіваюся, що допоможе тобі.
користувач8510915

Відповіді:


267

У Windows можна спробувати цю програму http://www.nirsoft.net/utils/opened_files_view.html, щоб дізнатись, чи обробляє файл db. Спробуйте закрити цю програму для розблокування бази даних

У Linux та macOS ви можете зробити щось подібне, наприклад, якщо ваш заблокований файл є development.db:

$ fuser development.db

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

> development.db: 5430

Просто вбити процес ...

вбити -9 5430

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


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

Більш простим рішенням буде просто перезавантажити комп'ютер.
чача15

7
@ chacham15: ви припускаєте, що база даних є на "моєму" комп'ютері, і ви ігноруєте можливість безлічі важливих процесів, що працюють на тому ж комп'ютері, що і той, з заблокованою базою даних. "Простіше" рішення ніколи не таке просте;)
tzot

1
@KyleCarlson - sqlite і mysql є фундаментально різними в цьому аспекті. З браузером SQLite-db немає нічого особливо поганого.
Беррі Цакала

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

90

Я змусив заблокувати свій db 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
вокі

Не працює дляFOREIGN KEY constraint failed (RELEASE RESTOREPOINT)
gies0r

52

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

Сторінка вікі SQLite DatabaseIsLocked пропонує хороше пояснення цього повідомлення про помилку. Частково вказується, що джерело суперечки є внутрішнім (до процесу, що видає помилку).

Те, що ця сторінка не пояснює, - це те, як SQLite вирішує, що щось у вашому процесі є блокувальним і які умови можуть призвести до помилкового позитиву.


2
Проблема полягає в тому, що сторінка або неправильна, або застаріла: у мене процес, який робить буквально нічого, окрім однієї ВСТАВКИ, яка отримує таке заблоковане повідомлення: неможливо, щоб цей процес спричинив блокування. Проблема була в іншому процесі розмови з тією ж БД.
Ден Джеймсон

4
@ converter42 Посилання зламано.
Оле Танге

32

Видалення файлу -journal звучить як жахлива ідея. Це там, щоб дозволити sqlite повертати базу даних до послідовного стану після аварії. Якщо ви видалите його, коли база даних перебуває в непослідовному стані, вам залишається пошкоджена база даних. Посилаючись на сторінку з сайту sqlite :

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

Ми підозрюємо, що звичайний режим відмови для відновлення SQLite відбувається так: відбувається збою живлення. Після відновлення живлення, добронамерений користувач або системний адміністратор починає оглядатися на диску на предмет пошкоджень. Вони бачать файл своєї бази даних під назвою "important.data". Цей файл, можливо, їм знайомий. Але після аварії є також гарячий журнал під назвою "важливий.дата-журнал". Потім користувач видаляє гарячий журнал, думаючи, що вони допомагають очистити систему. Ми не знаємо жодного способу запобігти цьому, крім навчання користувачів.

Відкат, як передбачається, відбудеться автоматично наступного разу, коли база даних буде відкрита, але вона вийде з ладу, якщо процес не зможе заблокувати базу даних. Як говорили інші, одна з можливих причин цього полягає в тому, що в даний час відкритий інший процес. Іншою можливістю є несвіжий замок NFS, якщо база даних містить обсяг NFS. У цьому випадку вирішення завдання полягає в заміні файлу бази даних на свіжу копію, яка не заблокована на сервері NFS (mv database.db original.db; cp original.db database.db). Зауважте, що FAQ FAQ рекомендує бути обережними щодо паралельного доступу до баз даних на томах NFS через помилкові реалізації блокування файлів NFS.

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

До речі, наявність файлу -journal не обов'язково означає, що стався збій або що є зміни, які потрібно відкотити назад. У Sqlite є кілька різних режимів журналу, і в режимах PERSIST або TRUNCATE він залишає файл -journal завжди на місці і змінює вміст, щоб вказати, чи є часткові транзакції для відкочування.


23

Якщо ви хочете видалити помилку "база даних заблокована", виконайте наступні дії:

  1. Скопіюйте файл бази даних в інше місце.
  2. Замініть базу даних скопійованою базою даних. Це призведе до знецінення всіх процесів, які мали доступ до файлу вашої бази даних.

2
Я спробував "fuser <DB>", як описано вище, але не вийшло. Цей простий крок працює для мене.
Джекі Єх

У моєму випадку мені також довелося перезапустити ноутбук Юпітера.
Віктор

15

Якщо процес має блокування в БД SQLite і виходить з ладу, БД залишається заблокованим постійно. У цьому проблема. Справа не в тому, що якийсь інший процес має блокування.


48
так як розблокувати db?
Ерік Каплун

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

13

файли db SQLite - це лише файли, тому першим кроком було б переконатися, що він не лише для читання. Інше, що потрібно зробити, це переконатися, що у вас немає якогось переглядача БД GUI SQLite з відкритою БД. Ви можете відкрити БД в іншій оболонці, або ваш код може мати відкриту БД. Як правило, ви побачите це, якщо інший потік або додаток, такий як браузер SQLite Database, відкриває для запису БД.


4
На мій досвід, браузер SQLite Database Browser (SDB) відтворює блокування бази даних, якщо ви редагуєте в ній дані, але потім не зберігаєте їх у SDB. Якщо ви збережете його, він звільнить замок.
Челоніан

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

10

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

Рецепти відновлення, запропоновані вище, для мене не спрацювали (включаючи ідею спершу перемістити та скопіювати назад базу даних). Але після копіювання її до системи, що не належить до NFS, база даних стала придатною для використання, і дані, схоже, не втратили.


9

Моє блокування було спричинене збоєм системи, а не зависанням. Щоб вирішити це, я просто перейменував файл, а потім скопіював його до оригінального імені та місця.

Використання оболонки Linux, яка ...

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

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


4

Я знайшов документацію різних станів блокування в SQLite дуже корисною. Майкл, якщо ви можете виконувати читання, але не можете виконувати записи в базу даних, це означає, що процес отримав заблокований замок у вашій базі даних, але ще не виконав запис. Якщо ви використовуєте SQLite3, є новий замок під назвою ПЕЧЕННЯ, де більше підключення більше не дозволено, але існуючі з'єднання можуть виконувати зчитування, тож якщо це проблема, вам слід поглянути на це.


4

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


3

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

НЕ ЗАБУДУЙТЕ ЗАДАЧИТИ:

sqlite_reset(xxx);

або

sqlite_finalize(xxx);

3

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

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

Я ще раз зазначу, бо важливо - рішення НЕ знайти програму блокування та вбити її - це з’ясувати, чи в базі даних є блокування запису з поважної причини, і піти звідти. Іноді правильним рішенням є просто перерва на каву.

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

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


2

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

Однак було б непогано мати можливість виявити першопричину.


2

Команда lsof у моєму середовищі Linux допомогла мені зрозуміти, що процес висить, зберігаючи файл відкритим.
Загинув процес і проблема була вирішена.


2

Це посилання вирішує проблему. : Коли Sqlite дає: Помилка заблокованої бази даних Це вирішило, що моя проблема може бути корисною для вас.

І ви можете використовувати розпочати транзакцію та закінчити транзакцію, щоб не робити базу даних заблокованою в майбутньому.


2

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

  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 я виявив, що я не закрив одну оболонку, яка використовувала db. Просто закрийте його і спробуйте ще раз;)


1

У мене була така ж проблема. Мабуть, функція відкату, здається, перезаписує файл db з журналу, який такий же, як і файл db, але без останньої зміни. Я реалізував це в своєму коді нижче, і з тих пір він працює нормально, тоді як раніше мій код просто застряг у циклі, оскільки база даних залишалася заблокованою.

Сподіваюсь, це допомагає

мій пітон код

##############
#### 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 (Manag.py) за допомогою бази даних.


1

Давнє запитання, з великою кількістю відповідей, ось кроки, за якими я нещодавно виконував читання відповідей вище, але в моєму випадку проблема була пов’язана з спільним використанням ресурсів cifs. Про цю справу раніше не повідомлялося, тому сподівайтеся, що вона комусь допоможе.

  • Перевірте, чи немає у вашому Java-коді відкритих з’єднань.
  • Перевірте, чи не використовуються інші процеси вашого db-файлу SQLite з lsof.
  • Перевірте, чи має власник вашого запущеного jvm процесу доступ до r / w над файлом.
  • Спробуйте застосувати режим блокування на розмиканні з'єднання за допомогою

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

Якщо ви використовуєте свій db-файл 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 сервери. На 2 серверах я міг успішно виконувати запити в базі даних, на третьому думав, що я отримую повідомлення "база даних заблокована".

Справа в цій третій машині полягала в тому, що на ній не залишилося місця /var. Кожен раз, коли я намагався запустити запит у БУДЬ-яку базу даних SQLite, що знаходиться в цій файловій системі, я отримував повідомлення "база даних заблоковано", а також ця помилка в журналах:

8 серпня 10:33:38 сервер01 ядро: lockd: не можу контролювати 172.22.84.87

І цей також:

8 серпня 10:33:38 server01 rpc.statd [7430]: Не вдалося вставити: write /var/lib/nfs/statd/sm/other.server.name.com: На пристрої не залишилось місця, 8 серпня 10:33: 38 сервер01 rpc.statd [7430]: STAT_FAIL до сервера01 для 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

З попередніх коментарів ви сказали, що присутні файл -журналу.

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

Перезапустивши процес 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.