sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked
Як розблокувати базу даних, щоб це спрацювало?
sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked
Як розблокувати базу даних, щоб це спрацювало?
Відповіді:
У Windows можна спробувати цю програму http://www.nirsoft.net/utils/opened_files_view.html, щоб дізнатись, чи обробляє файл db. Спробуйте закрити цю програму для розблокування бази даних
У Linux та macOS ви можете зробити щось подібне, наприклад, якщо ваш заблокований файл є development.db:
$ fuser development.db
Ця команда покаже, який процес блокує файл:
> development.db: 5430
Просто вбити процес ...
вбити -9 5430
... І ваша база даних буде розблокована.
kill
повинно бути добре, але вам потрібно бути обережним, щоб його вбити належним чином, і kill -9
, ймовірно, неправильно та / або надмірно. Якщо процес висів і не буде інакше загинути, іноді це потрібно kill -9
. Але ви не хочете йти і вбивати основну виробничу роботу, щоб ви могли повідомити, що база даних вже не заблокована!
Я змусив заблокувати свій db sqlite через збій програми під час запису. Ось як я це виправив:
echo ".dump" | sqlite old.db | sqlite new.db
Взято з: http://random.kakaopor.hu/how-to-repair-an-sqlite-database
sqlite> .dump PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; /**** ERROR: (5) database is locked *****/ ROLLBACK; -- due to errors
FOREIGN KEY constraint failed (RELEASE RESTOREPOINT)
Сторінка DatabaseIsLocked, перелічена нижче, більше не доступна. Сторінка блокування та паралельності файлів описує зміни, пов’язані з блокуванням файлів, введені в v3 і можуть бути корисними для майбутніх читачів. https://www.sqlite.org/lockingv3.html
Сторінка вікі SQLite DatabaseIsLocked пропонує хороше пояснення цього повідомлення про помилку. Частково вказується, що джерело суперечки є внутрішнім (до процесу, що видає помилку).
Те, що ця сторінка не пояснює, - це те, як SQLite вирішує, що щось у вашому процесі є блокувальним і які умови можуть призвести до помилкового позитиву.
Видалення файлу -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 завжди на місці і змінює вміст, щоб вказати, чи є часткові транзакції для відкочування.
Якщо ви хочете видалити помилку "база даних заблокована", виконайте наступні дії:
Якщо процес має блокування в БД SQLite і виходить з ладу, БД залишається заблокованим постійно. У цьому проблема. Справа не в тому, що якийсь інший процес має блокування.
файли db SQLite - це лише файли, тому першим кроком було б переконатися, що він не лише для читання. Інше, що потрібно зробити, це переконатися, що у вас немає якогось переглядача БД GUI SQLite з відкритою БД. Ви можете відкрити БД в іншій оболонці, або ваш код може мати відкриту БД. Як правило, ви побачите це, якщо інший потік або додаток, такий як браузер SQLite Database, відкриває для запису БД.
У мене виникли ці проблеми саме зараз, використовуючи базу даних SQLite на віддаленому сервері, що зберігається на кріпленні NFS. SQLite не змогла отримати блокування після того, як віддалений сеанс оболонки, який я використав, зазнав аварії, коли база даних була відкрита.
Рецепти відновлення, запропоновані вище, для мене не спрацювали (включаючи ідею спершу перемістити та скопіювати назад базу даних). Але після копіювання її до системи, що не належить до NFS, база даних стала придатною для використання, і дані, схоже, не втратили.
Моє блокування було спричинене збоєм системи, а не зависанням. Щоб вирішити це, я просто перейменував файл, а потім скопіював його до оригінального імені та місця.
Використання оболонки Linux, яка ...
mv mydata.db temp.db
cp temp.db mydata.db
Я додав " Pooling=true
" до рядка з'єднання, і він працював.
Я знайшов документацію різних станів блокування в SQLite дуже корисною. Майкл, якщо ви можете виконувати читання, але не можете виконувати записи в базу даних, це означає, що процес отримав заблокований замок у вашій базі даних, але ще не виконав запис. Якщо ви використовуєте SQLite3, є новий замок під назвою ПЕЧЕННЯ, де більше підключення більше не дозволено, але існуючі з'єднання можуть виконувати зчитування, тож якщо це проблема, вам слід поглянути на це.
У мене є така проблема в додатку, який отримує доступ до SQLite з 2-х з'єднань - одне було лише для читання, а друге для запису та читання. Схоже, що з'єднання, яке доступне лише для читання, блокувало запис із другого з'єднання. Нарешті, виявляється, що потрібно доопрацювати або, принаймні, скинути підготовлені заяви негайно після використання. Поки не було відкрито підготовлену операцію, це спричинило, що база даних була заблокована для запису.
НЕ ЗАБУДУЙТЕ ЗАДАЧИТИ:
sqlite_reset(xxx);
або
sqlite_finalize(xxx);
Деякі функції, такі як 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 у файлі.
У мене просто трапилося щось подібне - мій веб-додаток міг читати з бази даних, але не міг виконувати жодних вставок чи оновлень. Перезавантаження Apache вирішило проблему хоча б тимчасово.
Однак було б непогано мати можливість виявити першопричину.
Це посилання вирішує проблему. : Коли Sqlite дає: Помилка заблокованої бази даних Це вирішило, що моя проблема може бути корисною для вас.
І ви можете використовувати розпочати транзакцію та закінчити транзакцію, щоб не робити базу даних заблокованою в майбутньому.
Повинна бути внутрішня проблема бази даних ...
Для мене це виявилося після спроби перегляду бази даних за допомогою "SQLite manager" ...
Отже, якщо ви не можете знайти інший процес підключення до бази даних, і ви просто не можете його виправити, просто спробуйте це радикальне рішення:
rake db:migrate
"Я зіткнувся з цією ж проблемою на Mac OS X 10.5.7 із запуском сценаріїв Python з термінального сеансу. Хоча я зупинив сценарії і вікно терміналу сиділо в командному рядку, воно призведе до цієї помилки наступного разу, коли вона запуститься. Рішенням було закрити вікно терміналу, а потім знову відкрити його. Для мене це не має сенсу, але це спрацювало.
У мене була така ж проблема. Мабуть, функція відкату, здається, перезаписує файл 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 )
Однією з поширених причин отримання цього винятку є те, що ви намагаєтеся зробити операцію запису, зберігаючи ресурси для операції зчитування. Наприклад, якщо ви ВИБІРАЄТЬСЯ з таблиці, а потім спробуйте оновити щось, що ви вибрали, не закриваючи попередньо ResultSet.
У мене було помилки "база даних заблокована" у багатопотоковому додатку, який, як видається, є результатом коду SQLITE_BUSY , і я вирішив це, встановивши sqlite3_busy_timeout на щось підходяще, як 30000.
(Зі сторони, як це не дивно, що у 7-річному питанні цього ніхто ще не з'ясував! SQLite справді - це своєрідний і дивовижний проект ...)
Перш ніж перейти до опції перезавантаження, варто дізнатися, чи зможете ви знайти користувача бази даних 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) за допомогою бази даних.
Давнє запитання, з великою кількістю відповідей, ось кроки, за якими я нещодавно виконував читання відповідей вище, але в моєму випадку проблема була пов’язана з спільним використанням ресурсів cifs. Про цю справу раніше не повідомлялося, тому сподівайтеся, що вона комусь допоможе.
Спробуйте застосувати режим блокування на розмиканні з'єднання за допомогою
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
Я отримав цю помилку в сценарії, трохи відрізняється від описаного тут.
База даних 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
Після вирішення космічної ситуації все прийшло в норму.
Якщо ви намагаєтесь розблокувати базу даних 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
З попередніх коментарів ви сказали, що присутні файл -журналу.
Це може означати, що ви відкрили та (ЕКСКЛЮЗИВНО?) Транзакцію та ще не скористалися даними. Чи залишила ваша програма чи інший процес позаду журнал ??
Перезапустивши процес sqlite, перегляньте файл журналу та очистіть всі невдалі дії та видаліть файл -journal.
Як сказав Сеун Осева, іноді процес зомбі буде сидіти в терміналі із замком, що має замок, навіть якщо ви не вважаєте, що це можливо. Ваш сценарій запускається, виходить з ладу, і ви повертаєтесь до підказки, але процес зомбі десь породжений викликом бібліотеки, і цей процес заблокований.
Закриття терміналу, в якому ви були (на OSX), може спрацювати. Перезавантаження працюватиме. Ви можете шукати "python" процеси (наприклад), які нічого не роблять, і вбивати їх.
ви можете спробувати це: .timeout 100
встановити тайм-аут. Я не знаю, що трапиться в командному рядку, але в C # .Net, коли я це роблю: "UPDATE table-name SET column-name = value;"
я отримую, що база даних заблокована, але "UPDATE table-name SET column-name = value"
це йде добре.
Схоже, коли ви додасте; sqlite шукатиме подальшу команду.