Jak odblokować bazę danych SQLite?


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

Jak odblokować bazę danych, aby działało?


Może istnieć inny proces uzyskujący dostęp do pliku bazy danych - czy sprawdziłeś lsof?
nieistniejący

Miałem ten sam problem, problem był w programie antywirusowym, kiedy go dezaktywowałem, moja aplikacja działa dobrze, ale kiedy go aktywuję, znajduję błąd „baza danych jest zablokowana”, mam nadzieję, że to pomoże.
user8510915

Odpowiedzi:


267

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.


19
... z oczywistym zastrzeżeniem, że musisz wiedzieć, co robisz. Jeśli jest to nieistotny proces, to killpowinno być w porządku, ale musisz uważać, aby go odpowiednio zabić i kill -9prawdopodobnie 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!
tripleee

Prostszym rozwiązaniem byłoby po prostu zrestartowanie komputera.
chacham15,

7
@ chacham15: zakładasz, że baza danych znajduje się na „moim” komputerze i ignorujesz możliwość wielu ważnych procesów uruchomionych na tym samym komputerze, co ten z zablokowaną bazą danych. „Prostsze” rozwiązanie nigdy nie jest takie proste;)
tzot 30.01.2013

1
@KyleCarlson - sqlite i mysql zasadniczo różnią się pod tym względem. Nie ma nic szczególnie złego w przeglądarce SQLite-db-browser.
Berry Tsakala,

6
To rozwiązanie zakłada, że ​​istnieje proces blokujący plik. Możliwe, że proces się zawiesił, pozostawiając plik SQLite w stanie niezdatnym do użytku. W takim przypadku zobacz moją odpowiedź.
Robert

90

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


4
sqlite3:sqlite> .dump PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; /**** ERROR: (5) database is locked *****/ ROLLBACK; -- due to errors
woky

Nie działa dlaFOREIGN KEY constraint failed (RELEASE RESTOREPOINT)
gies0r

52

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.


2
Problem polega na tym, że strona jest niepoprawna lub nieaktualna: mam proces, który dosłownie nic nie robi, ale tylko jeden WSTAW, który otrzymuje ten zablokowany komunikat: nie jest możliwe, aby ten proces spowodował blokadę. Problem polegał na innym procesie rozmowy z tym samym DB.
Dan Jameson

4
@ converter42 Link uszkodzony.
Ole Tange

32

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.


23

Jeśli chcesz usunąć błąd „baza danych jest zablokowana”, wykonaj następujące kroki:

  1. Skopiuj plik bazy danych do innej lokalizacji.
  2. Zastąp bazę danych skopiowaną bazą danych. Spowoduje to wyłączenie wszystkich procesów, które uzyskiwały dostęp do pliku bazy danych.

2
Próbowałem „fuser <DB>” jak opisano powyżej, ale nie działało. Te proste kroki działają dla mnie.
Jackie Yeh,

W moim przypadku musiałem również ponownie uruchomić Notatnik Jupyter.
Victor

15

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ę.


48
więc jak odblokować db?
Erik Kaplun

4
To po prostu nieprawda. Blokady są utrzymywane przez system operacyjny. Przeczytaj odpowiedź poniżej.
JJ

13

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.


4
Z mojego doświadczenia wynika, że ​​SQLite Database Browser (SDB) odtwarzalnie blokuje bazę danych, jeśli edytujesz za jej pomocą dane, ale nie zapisujesz ich w SDB. Jeśli go zapiszesz, zwolni blokadę.
Chelonian

Mogę wstawić, ale nie mogę usunąć.
Wennie

10

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.


9

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

bardzo proste rozwiązanie, rozwiązujące mój problem zablokowanej bazy danych na dysku sieciowym.
Maverick2805,


4

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ć.


4

Ten błąd może zostać zgłoszony, jeśli plik znajduje się w folderze zdalnym, takim jak folder współdzielony. Zmieniłem bazę danych na katalog lokalny i działała idealnie.


3

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);

3

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 ENDpóź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 EXCLUSIVEzażą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.


2

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ę.


2

Polecenie lsof w moim środowisku Linux pomogło mi zorientować się, że proces zawiesza się, utrzymując otwarty plik.
Zabił proces i problem został rozwiązany.



2

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:

  1. Zapewnij, aby wyeksportować swoje tabele (możesz użyć „SQLite manager” w Firefox)
  2. Jeśli migracja zmieni schemat bazy danych, usuń ostatnią nieudaną migrację
  3. Zmień nazwę pliku „database.sqlite”
  4. Uruchom „rake db: migrate”, aby utworzyć nową działającą bazę danych
  5. Podaj, aby dać odpowiednie uprawnienia do bazy danych do importowania tabeli
  6. Zaimportuj tabele zapasowe
  7. Napisz nową migrację
  8. Wykonaj to za pomocą „ rake db:migrate

1

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.


1

Właśnie miałem ten sam błąd. Po 5 minutach wyszukiwania w Google stwierdziłem, że nie zamknąłem żadnej powłoki, która używała bazy danych. Po prostu zamknij i spróbuj ponownie;)


1

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

mój kod 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 )

1

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.


1

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 ...)


1

Przed przejściem do opcji ponownego uruchomienia warto sprawdzić, czy możesz znaleźć użytkownika bazy danych sqlite.

W systemie Linux można fuserw 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.


1

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.

  • Sprawdź, czy w kodzie Java nie ma otwartych połączeń.
  • Sprawdź, czy żadne inne procesy nie używają pliku db SQLite z lsof.
  • Sprawdź, czy właściciel użytkownika działającego procesu jvm ma uprawnienia do r / w nad plikiem.
  • 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

1

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.


1

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

0

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.


0

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.


0

możesz spróbować: .timeout 100ustawić 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ń.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.