sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked
Jak odblokować bazę danych, aby działało?
sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked
Jak odblokować bazę danych, aby działało?
Odpowiedzi:
W systemie Windows możesz wypróbować ten program http://www.nirsoft.net/utils/opened_files_view.html, aby dowiedzieć się, że proces obsługuje plik db. Spróbuj zamknąć ten program w celu odblokowania bazy danych
W systemie Linux i macOS możesz zrobić coś podobnego, na przykład, jeśli zablokowany plik to programowanie.db:
$ fuser development.db
To polecenie pokaże, jaki proces blokuje plik:
> development.db: 5430
Po prostu zabij ten proces ...
zabij -9 5430
... A twoja baza danych zostanie odblokowana.
kill
powinno być w porządku, ale musisz uważać, aby go odpowiednio zabić i kill -9
prawdopodobnie jest to błąd i / lub przesada. Jeśli proces zostanie zawieszony i inaczej nie umrze, czasem potrzebujesz kill -9
. Ale nie chcesz iść i zabijać głównego zadania produkcyjnego, abyś mógł zgłosić, że baza danych nie jest już zablokowana!
Powodowałem, że moja db sqlite została zablokowana przez awarię aplikacji podczas zapisu. Oto jak to naprawiłem:
echo ".dump" | sqlite old.db | sqlite new.db
Zaczerpnięte z: 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)
Wymieniona poniżej strona DatabaseIsLocked nie jest już dostępna. Strona Blokowanie plików i współbieżność opisuje zmiany związane z blokowaniem plików wprowadzone w v3 i mogą być przydatne dla przyszłych czytelników. https://www.sqlite.org/lockingv3.html
Strona SQLite Wiki DatabaseIsLocked oferuje dobre wyjaśnienie tego komunikatu o błędzie. Po części stwierdza, że źródło niezgody ma charakter wewnętrzny (dla procesu powodującego błąd).
Ta strona nie wyjaśnia, w jaki sposób SQLite decyduje, że coś w twoim procesie ma blokadę i jakie warunki mogą prowadzić do fałszywie pozytywnego wyniku.
Usunięcie pliku -journal brzmi jak okropny pomysł. Ma to umożliwić sqlite przywrócenie bazy danych do spójnego stanu po awarii. Jeśli usuniesz go, gdy baza danych jest niespójna, pozostanie uszkodzona baza danych. Powołując się na stronę z witryny sqlite :
Jeśli nastąpi awaria lub utrata zasilania, a na dysku pozostanie gorący dziennik, ważne jest, aby oryginalny plik bazy danych i gorący dziennik pozostały na dysku z ich oryginalnymi nazwami, dopóki plik bazy danych nie zostanie otwarty przez inny proces SQLite i wycofany . [...]
Podejrzewamy, że typowy tryb awarii odzyskiwania SQLite wygląda następująco: występuje awaria zasilania. Po przywróceniu zasilania zdrowy użytkownik lub administrator systemu zaczyna rozglądać się na dysku w poszukiwaniu uszkodzeń. Widzą swój plik bazy danych o nazwie „ważny.data”. Ten plik jest może im znany. Ale po awarii jest też gorący dziennik o nazwie „ważny.data-dziennik”. Następnie użytkownik usuwa gorący dziennik, myśląc, że pomaga oczyścić system. Nie wiemy, jak temu zapobiec, poza edukacją użytkowników.
Wycofanie powinno nastąpić automatycznie przy następnym otwarciu bazy danych, ale zakończy się niepowodzeniem, jeśli proces nie będzie mógł zablokować bazy danych. Jak powiedzieli inni, jednym z możliwych powodów jest to, że inny proces ma go obecnie otwarty. Inną możliwością jest przestarzała blokada NFS, jeśli baza danych znajduje się na wolumenie NFS. W takim przypadku obejściem problemu jest zastąpienie pliku bazy danych świeżą kopią, która nie jest zablokowana na serwerze NFS (mv database.db original.db; cp original.db database.db). Zauważ, że FAQ sqlite zaleca ostrożność w zakresie równoczesnego dostępu do baz danych na woluminach NFS, ze względu na błędne implementacje blokowania plików NFS.
Nie potrafię wyjaśnić, dlaczego usunięcie pliku -journal pozwoliłoby zablokować bazę danych, której wcześniej nie mogłeś. Czy to jest powtarzalne?
Nawiasem mówiąc, obecność pliku -journal niekoniecznie oznacza, że nastąpiła awaria lub że istnieją zmiany, które należy wycofać. Sqlite ma kilka różnych trybów dziennika, aw trybach PERSIST lub TRUNCATE zawsze pozostawia plik -journal na swoim miejscu i zmienia zawartość, aby wskazać, czy istnieją częściowe transakcje do wycofania.
Jeśli chcesz usunąć błąd „baza danych jest zablokowana”, wykonaj następujące kroki:
Jeśli proces ma blokadę na SQLite DB i ulega awarii, DB pozostaje zablokowane na stałe. To jest problem. To nie jest tak, że jakiś inny proces ma blokadę.
pliki db SQLite są tylko plikami, więc pierwszym krokiem byłoby upewnienie się, że nie są one tylko do odczytu. Inną rzeczą jest upewnienie się, że nie masz przeglądarki GUI SQLite DB z otwartą bazą danych. Możesz mieć otwartą bazę danych w innej powłoce lub twój kod może mieć otwartą bazę danych. Zazwyczaj jest to widoczne, jeśli inny wątek lub aplikacja, taka jak SQLite Database Browser, ma otwartą bazę danych do zapisu.
Właśnie miałem ten problem, używając bazy danych SQLite na zdalnym serwerze, przechowywanej na wierzchowcu NFS. SQLite nie był w stanie uzyskać blokady po awarii sesji zdalnej powłoki, której użyłem, gdy baza danych była otwarta.
Przepisy dotyczące odzyskiwania sugerowane powyżej nie działały dla mnie (w tym pomysł, aby najpierw przenieść, a następnie skopiować bazę danych z powrotem). Ale po skopiowaniu go do systemu innego niż NFS baza danych stała się użyteczna i nie wydaje się, że dane zostały utracone.
Moja blokada została spowodowana awarią systemu, a nie zawieszeniem się. Aby rozwiązać ten problem, po prostu zmieniłem nazwę pliku, a następnie skopiowałem go z powrotem do oryginalnej nazwy i lokalizacji.
Korzystanie z powłoki linux, która byłaby ...
mv mydata.db temp.db
cp temp.db mydata.db
Dodałem „ Pooling=true
” do ciągu połączenia i zadziałało.
Uważam, że dokumentacja różnych stanów blokowania w SQLite jest bardzo pomocna. Michael, jeśli możesz wykonywać odczyty, ale nie możesz zapisywać do bazy danych, oznacza to, że proces uzyskał ZAREZERWOWANĄ blokadę w bazie danych, ale jeszcze nie wykonał zapisu. Jeśli używasz SQLite3, istnieje nowa blokada o nazwie PENDING, w której nie można już łączyć żadnych procesów, ale istniejące połączenia mogą wykonywać odczyty, więc jeśli to jest problem, powinieneś na to spojrzeć.
Mam taki problem w aplikacji, który ma dostęp do SQLite z 2 połączeń - jedno było tylko do odczytu, a drugie do pisania i czytania. Wygląda na to, że to połączenie tylko do odczytu zablokowało zapis z drugiego połączenia. Wreszcie okazuje się, że po użyciu konieczne jest sfinalizowanie lub przynajmniej zresetowanie przygotowanych instrukcji. Do momentu otwarcia przygotowanej instrukcji spowodowało to, że baza danych została zablokowana do zapisu.
NIE ZAPOMNIJ:
sqlite_reset(xxx);
lub
sqlite_finalize(xxx);
Niektóre funkcje, takie jak INDEX'ing, mogą zająć bardzo dużo czasu - i podczas działania blokuje całą bazę danych. W takich przypadkach może nawet nie używać pliku dziennika!
Tak więc najlepszym / jedynym sposobem sprawdzenia, czy baza danych jest zablokowana, ponieważ proces AKTYWNIE zapisuje do niej (i dlatego powinieneś zostawić ją w spokoju, dopóki jej operacja nie zostanie zakończona) to dwukrotne skopiowanie pliku md5 (lub md5sum w niektórych systemach) . Jeśli otrzymasz inną sumę kontrolną, baza danych jest zapisywana i naprawdę NAPRAWDĘ nie chcesz zabić -9 tego procesu, ponieważ możesz łatwo skończyć z uszkodzoną tabelą / bazą danych.
Powtórzę, ponieważ jest to ważne - rozwiązaniem NIE jest znalezienie programu blokującego i zabicie go - to sprawdzenie, czy baza danych ma blokadę zapisu z dobrego powodu, i idź stamtąd. Czasami właściwym rozwiązaniem jest przerwa na kawę.
Jedynym sposobem na utworzenie takiej sytuacji zablokowania, ale nie zapisania, jest uruchomienie programu BEGIN EXCLUSIVE
, ponieważ chciał on dokonać pewnych zmian w tabeli lub czegoś podobnego, a następnie z jakiegokolwiek powodu nigdy nie wysyła END
później, a proces nigdy się nie kończy . Wszystkie trzy warunki, które są spełnione, są mało prawdopodobne w poprawnie napisanym kodzie, i jako takie 99 razy na 100, gdy ktoś chce zabić -9 ich procesu blokowania, proces blokowania faktycznie blokuje bazę danych z dobrego powodu. Programiści zazwyczaj nie dodająBEGIN EXCLUSIVE
warunku, chyba że naprawdę tego potrzebują, ponieważ zapobiega to współbieżności i zwiększa liczbę skarg użytkowników. Sam SQLite dodaje go tylko wtedy, gdy jest naprawdę potrzebny (na przykład podczas indeksowania).
Wreszcie status „zablokowany” nie istnieje WEWNĄTRZ pliku, jak podano kilka odpowiedzi - znajduje się on w jądrze systemu operacyjnego. Uruchomiony proces BEGIN EXCLUSIVE
zażądał od systemu operacyjnego blokady pliku. Nawet jeśli Twój wyłączny proces się zawiesił, Twój system operacyjny będzie w stanie dowiedzieć się, czy powinien utrzymać blokadę pliku, czy nie !! Nie jest możliwe, aby baza danych była zablokowana, ale żaden proces nie blokuje jej aktywnie !! Jeśli chodzi o sprawdzenie, który proces blokuje plik, zwykle lepiej jest użyć lsof zamiast fuser (jest to dobry przykład, dlaczego: /unix/94316/fuser-vs-lsof- sprawdzić pliki w użyciu ). Alternatywnie, jeśli masz DTrace (OSX), możesz użyć iosnoop na pliku.
Właśnie przydarzyło mi się coś podobnego - moja aplikacja internetowa mogła czytać z bazy danych, ale nie mogła wykonywać żadnych wstawień ani aktualizacji. Ponowne uruchomienie Apache rozwiązało problem przynajmniej tymczasowo.
Byłoby jednak miło, aby móc znaleźć przyczynę.
Ten link rozwiązuje problem. : Gdy Sqlite podaje: Błąd blokady bazy danych To rozwiązało problem, który może być dla Ciebie przydatny.
Możesz także użyć opcji rozpoczęcia transakcji i zakończenia transakcji, aby nie blokować bazy danych w przyszłości.
Powinien to być wewnętrzny problem bazy danych ...
Dla mnie objawił się po próbie przeglądania bazy danych za pomocą „SQLite manager” ...
Jeśli więc nie możesz znaleźć innego procesu, połącz się z bazą danych i po prostu nie możesz go naprawić, po prostu wypróbuj to radykalne rozwiązanie:
rake db:migrate
”Ten sam problem napotkałem w systemie Mac OS X 10.5.7, uruchamiając skrypty Python z sesji terminalowej. Mimo że zatrzymałem skrypty, a okno terminala znajdowało się w wierszu polecenia, przy następnym uruchomieniu dałoby ten błąd. Rozwiązaniem było zamknięcie okna terminala, a następnie otwarcie go ponownie. Dla mnie to nie ma sensu, ale zadziałało.
Miałem ten sam problem. Najwyraźniej funkcja wycofywania wydaje się zastępować plik db dziennikiem, który jest taki sam jak plik db, ale bez ostatniej zmiany. Zaimplementowałem to w moim kodzie poniżej i od tego czasu działa dobrze, podczas gdy zanim mój kod utknął w pętli, gdy baza danych pozostała zablokowana.
Mam nadzieję że to pomoże
##############
#### 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 )
Jednym z powszechnych powodów występowania tego wyjątku jest próba wykonania operacji zapisu, przy jednoczesnym utrzymaniu zasobów dla operacji odczytu. Na przykład, jeśli wybierzesz z tabeli, a następnie spróbujesz zaktualizować coś, co wybrałeś, bez uprzedniego zamknięcia zestawu wyników.
Miałem również błędy „baza danych jest zablokowana” w aplikacji wielowątkowej, która wydaje się być kodem wynikowym SQLITE_BUSY , i rozwiązałem go, ustawiając sqlite3_busy_timeout na coś odpowiednio długiego jak 30000.
(Na marginesie, jak dziwne, że na 7-letnie pytanie nikt tego jeszcze nie odkrył! SQLite jest naprawdę osobliwym i niesamowitym projektem ...)
Przed przejściem do opcji ponownego uruchomienia warto sprawdzić, czy możesz znaleźć użytkownika bazy danych sqlite.
W systemie Linux można fuser
w tym celu zastosować:
$ fuser database.db
$ fuser database.db-journal
W moim przypadku otrzymałem następującą odpowiedź:
philip 3556 4700 0 10:24 pts/3 00:00:01 /usr/bin/python manage.py shell
Co pokazało, że mam inny program Python z pid 3556 (manage.py) korzystający z bazy danych.
Stare pytanie, z dużą ilością odpowiedzi, oto kroki, które ostatnio wykonałem, czytając powyższe odpowiedzi, ale w moim przypadku problem był spowodowany udostępnianiem zasobów cifs. Ta sprawa nie została wcześniej zgłoszona, więc mam nadzieję, że komuś pomoże.
Spróbuj wymusić tryb blokady przy otwieraniu połączenia za pomocą
final SQLiteConfig config = new SQLiteConfig();
config.setReadOnly(false);
config.setLockingMode(LockingMode.NORMAL);
connection = DriverManager.getConnection(url, config.toProperties());
Jeśli używasz pliku db SQLite w folderze współdzielonym NFS, sprawdź ten punkt FAQ SQLite i przejrzyj opcje konfiguracji montowania, aby upewnić się, że unikasz blokad, jak opisano tutaj :
//myserver /mymount cifs username=*****,password=*****,iocharset=utf8,sec=ntlm,file,nolock,file_mode=0700,dir_mode=0700,uid=0500,gid=0500 0 0
Wystąpił ten błąd w scenariuszu nieco innym niż te opisane tutaj.
Baza danych SQLite opierała się na systemie plików NFS współdzielonym przez 3 serwery. Na 2 serwerach udało mi się pomyślnie uruchomić zapytania w bazie danych, na trzecim myślałem, że otrzymuję komunikat „Baza danych jest zablokowana”.
Problem z tą trzecią maszyną polegał na tym, że nie miała już wolnego miejsca /var
. Za każdym razem, gdy próbowałem uruchomić zapytanie w DOWOLNEJ bazie danych SQLite znajdującej się w tym systemie plików, pojawia się komunikat „Baza danych jest zablokowana”, a także ten błąd dotyczący dzienników:
8 sierpnia 10:33:38 jądro server01: lockd: nie można monitorować 172.22.84.87
A ten także:
8 sierpnia 10:33:38 server01 rpc.statd [7430]: Nie można wstawić: pisanie /var/lib/nfs/statd/sm/other.server.name.com: Brak miejsca na urządzeniu 8 sierpnia 10:33: 38 server01 rpc.statd [7430]: STAT_FAIL do server01 dla SM_MON z 172.22.84.87
Po załatwieniu sytuacji kosmicznej wszystko wróciło do normy.
Jeśli próbujesz odblokować bazę danych Chrome, aby wyświetlić ją za pomocą SQLite , zamknij 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
Prochowiec
~/Library/Application Support/Google/Chrome/Default/Web Data
Z poprzednich komentarzy powiedziałeś, że plik -journal był obecny.
Może to oznaczać, że otworzyłeś (WYŁĄCZNIE?) Transakcję i jeszcze nie zatwierdziłeś danych. Czy twój program lub jakiś inny proces pozostawił „dziennik” za sobą?
Ponowne uruchomienie procesu sqlite sprawdzi plik dziennika i wyczyści wszelkie nieprzyjęte działania i usunie plik -journal.
Jak powiedział Seun Osewa, czasami proces zombie będzie siedział w terminalu z zamkiem, nawet jeśli nie wydaje ci się to możliwe. Twój skrypt uruchamia się, ulega awarii i wracasz do monitu, ale gdzieś wywołanie biblioteki zombie wywołało gdzieś proces i ten proces ma blokadę.
Zamykanie terminalu, w którym byłeś (w OSX) może działać. Ponowne uruchomienie będzie działać. Możesz poszukać procesów „python” (na przykład), które nic nie robią, i zabić je.
możesz spróbować: .timeout 100
ustawić limit czasu. Nie wiem, co się dzieje w wierszu polecenia, ale w C # .Net, gdy to robię: "UPDATE table-name SET column-name = value;"
dostaję Baza danych jest zablokowana, ale "UPDATE table-name SET column-name = value"
to idzie dobrze.
Wygląda na to, że po dodaniu; sqlite będzie szukał dalszych poleceń.