SQLite veritabanının kilidini nasıl açabilirim?


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

Bunun çalışması için veritabanının kilidini nasıl açabilirim?


Veritabanı dosyasına erişen başka bir işlem olabilir - lsof'u kontrol ettiniz mi?
unexist

Ben aynı sorun vardı, ben benim app çalışması iyi devre dışı bıraktığınızda antivirüs oldu, ama ben etkinleştirmek ben bazı hata "veritabanı kilitli" bulmak, size yardımcı olacağını umuyoruz.
user8510915

Yanıtlar:


267

Windows'da bu programı deneyerek http://www.nirsoft.net/utils/opened_files_view.html deneyerek işlemi db dosyası ile çalıştığını öğrenebilirsiniz . Veritabanı kilidini açmak için bu programı kapatmayı deneyin

Linux ve macOS'ta, örneğin kilitli dosyanız development.db ise benzer bir şey yapabilirsiniz:

$ fuser development.db

Bu komut, dosyayı hangi işlemin kilitlediğini gösterecektir:

> development.db: 5430

Sadece süreci öldür ...

öldür -9 5430

... Ve veritabanınızın kilidi açılacak.


19
... ne yaptığınızı bilmeniz gereken bariz uyarı ile. Eğer önemsiz bir süreç varsa, o killzaman iyi olmalı, ancak düzgün bir şekilde öldürmeye dikkat etmelisiniz ve kill -9muhtemelen yanlış ve / veya aşırı derecede. İşlem asılırsa ve başka türlü ölmezse, bazen ihtiyacınız olur kill -9. Ancak, ana üretim işine gitmek ve onu öldürmek istemezsiniz, böylece veritabanının artık kilitli olmadığını bildirebilirsiniz!
tripleee

Daha basit çözüm sadece bilgisayarınızı yeniden başlatmak olacaktır.
chacham15

7
@ chacham15: veritabanının "benim" bilgisayarında olduğunu varsayarsınız ve kilitli veritabanıyla aynı bilgisayarda çalışan birçok önemli işlem olasılığını yoksayarsınız. “Daha basit” çözüm asla bu kadar basit değildir;)
tzot

1
@KyleCarlson - sqlite ve mysql bu açıdan temelden farklıdır. SQLite-db-tarayıcısında özellikle yanlış bir şey yoktur.
Berry Tsakala

6
Bu çözüm, dosyayı kilitleyen bir işlem olduğunu varsayar. SQLite dosyasını kullanılamaz bir durumda bırakarak bir işlemin çökmesi mümkündür. Bu durumda cevabımı görün.
Robert

90

Benim sqlite db yazma sırasında bir uygulama çökerek kilitli neden oldu. İşte nasıl düzelttim:

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

Alındığı yer: 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

İçin çalışmıyorFOREIGN KEY constraint failed (RELEASE RESTOREPOINT)
gies0r

52

Aşağıda listelenen DatabaseIsLocked sayfası artık mevcut değil. Dosya Kilitleme ve Eşzamanlılık sayfası, v3'te tanıtılan dosya kilitleme ile ilgili değişiklikleri açıklar ve gelecekteki okuyucular için yararlı olabilir. https://www.sqlite.org/lockingv3.html

SQLite wiki DatabaseIsLocked sayfası bu hata mesajının iyi bir açıklamasını sunar. Kısmen, çekişme kaynağının dahili olduğunu (hatayı yayan sürece) belirtir.

Bu sayfanın açıklamadığı şey, SQLite'nin işleminizdeki bir şeyin bir kilidi tuttuğuna ve hangi koşulların yanlış pozitifliğe yol açabileceğine nasıl karar verdiğidir.


2
Sorun şu sayfa ya yanlış ya da güncel değil: Kelimenin tam anlamıyla hiçbir şey yaptım ama bu kilitli mesajı alıyor tek bir INSERT bir işlem var: bu işlemin kilide neden olması mümkün değildir. Sorun aynı DB ile konuşmak başka bir süreçte oldu.
Dan Jameson

4
@ converter42 Bağlantı koptu.
Ole Tange

32

-Dergi dosyasını silmek korkunç bir fikir gibi geliyor. Bir çökme sonrasında sqlite'ın veritabanını tutarlı bir duruma geri döndürmesine izin vermek için orada. Veritabanı tutarsız bir durumdayken silerseniz, bozuk bir veritabanı kalır. Sqlite sitesinden bir sayfaya atıf :

Bir kilitlenme veya güç kaybı meydana gelirse ve diskte bir sıcak günlük kalırsa, veritabanı dosyası başka bir SQLite işlemi tarafından açılana ve geri alınana kadar, özgün veritabanı dosyasının ve sıcak günlüğün orijinal adlarıyla diskte kalması önemlidir. . [...]

SQLite kurtarma için ortak bir hata modunun şu şekilde gerçekleştiğinden şüpheleniyoruz: Bir elektrik kesintisi meydana gelir. Güç geri yüklendikten sonra, iyi niyetli bir kullanıcı veya sistem yöneticisi diskte hasar olup olmadığına bakmaya başlar. Veritabanı dosyasını "important.data" olarak görürler. Bu dosya belki de onlara tanıdık geliyor. Ancak çarpışmadan sonra "important.data-journal" adında sıcak bir dergi de var. Kullanıcı daha sonra sistemi temizlemeye yardımcı olduğunu düşünerek sıcak günlüğü siler. Bunu önlemek için kullanıcı eğitimi dışında bir yol bilmiyoruz.

Geri alma işlemi, veritabanı bir sonraki açılışında otomatik olarak gerçekleşir, ancak işlem veritabanını kilitleyemezse başarısız olur. Diğerlerinin söylediği gibi, bunun olası bir nedeni şu anda başka bir sürecin açık olmasıdır. Başka bir olasılık, veritabanı bir NFS birimindeyse eski bir NFS kilididir. Bu durumda, geçici çözüm, veritabanı dosyasını NFS sunucusunda kilitli olmayan yeni bir kopyayla (mv database.db original.db; cp original.db database.db) değiştirmektir. Sqlite SSS'nin, NFS dosya kilitlemesinin hatalı uygulamaları nedeniyle NFS birimlerindeki veritabanlarına eşzamanlı erişim konusunda dikkatli olmanızı önerdiğini unutmayın.

Bir dergi dosyasını silmenin neden daha önce yapamayacağınız bir veritabanını kilitlemenize izin vereceğini açıklayamıyorum. Bu tekrarlanabilir mi?

Bu arada, bir dergi dosyasının varlığı mutlaka bir çökme olduğu veya geri alınacak değişikliklerin olduğu anlamına gelmez. Sqlite birkaç farklı günlük moduna sahiptir ve PERSIST veya TRUNCATE modlarında -journal dosyasını her zaman yerinde bırakır ve geri alınacak kısmi işlem olup olmadığını göstermek için içeriği değiştirir.


23

"Veritabanı kilitli" hatasını kaldırmak istiyorsanız şu adımları izleyin:

  1. Veritabanı dosyanızı başka bir konuma kopyalayın.
  2. Veritabanını kopyalanan veritabanı ile değiştirin. Bu, veritabanı dosyanıza erişmekte olan tüm işlemleri engeller.

2
Yukarıda açıklandığı gibi 'kaynaştırıcı <DB>' denedim, ancak işe yaramadı. Bu basit adımlar benim için işe yarıyor.
Jackie Yeh

Benim durumumda da Jupyter Notebook'umu yeniden başlatmak zorunda kaldım.
Victor

15

Bir işlemin bir SQLite DB'sinde bir kilit varsa ve çökerse, DB kalıcı olarak kilitli kalır. İşte sorun bu. Başka bir işlemin kilidi olmadığı anlamına gelmez.


48
peki db kilidini nasıl?
Erik Kaplun

4
Bu doğru değil. Kilitler işletim sistemi tarafından sağlanır. Aşağıdaki cevabı okuyun.
JJ

13

SQLite db dosyaları sadece dosyalardır, bu nedenle ilk adım salt okunur olmadığından emin olmak olacaktır. Yapılması gereken diğer bir şey, DB açıkken GUI SQLite DB görüntüleyicisinin bir tür olmadığından emin olmaktır. DB başka bir kabukta açık olabilir veya kodunuz DB açık olabilir. Farklı bir iş parçacığı veya SQLite Veritabanı Tarayıcısı gibi bir uygulama DB yazmak için açıksa genellikle bunu görürsünüz.


4
Deneyimlerime göre, SQLite Veritabanı Tarayıcısı (SDB), bir veriyi onunla düzenlerseniz ancak daha sonra SDB'ye kaydetmezseniz tekrarlanabilir bir şekilde kilitler. Eğer kaydederseniz, kilidi serbest bırakır.
Chelonian

Ekleyebilirim ancak Silemiyorum.
Wennie

10

Ben şimdi, NFS mount saklanan uzak bir sunucuda bir SQLite veritabanı kullanarak bu sorunu vardı. SQLite veritabanı açıkken kullandığım uzak kabuk oturumu çöktükten sonra kilit alamadı.

Yukarıda önerilen kurtarma tarifleri benim için işe yaramadı (önce veritabanını geri taşıyıp sonra geri kopyalamak fikri dahil). Ancak bunu NFS olmayan bir sisteme kopyaladıktan sonra, veritabanı kullanılabilir hale geldi ve veri kaybedilmemiş gibi görünüyor.


9

Kilidim sistemin kilitlenmesi, asılı bir işlemden değil. Bunu çözmek için dosyayı yeniden adlandırdım ve orijinal adına ve konumuna kopyaladım.

Bir linux kabuğu kullanarak ...

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

bir ağ sürücüsünde kilitli bir veritabanı sorunumu çözerek çok kolay bir çözüm.
Maverick2805


4

SQLite çeşitli kilitleme durumlarının belgelerini çok yararlı buldum . Michael, okumaları gerçekleştirebilir ancak veritabanına yazma gerçekleştiremezseniz, bu, bir işlemin veritabanınızda REZERVED bir kilit aldığını, ancak henüz yazma işlemini gerçekleştirmediğini gösterir. SQLite3 kullanıyorsanız, daha fazla işlemin bağlanmasına izin verilmeyen ancak mevcut bağlantıların eşik değerleri okuma yapabileceği PENDING adlı yeni bir kilit var, bu yüzden bu sorun varsa bunun yerine bakmalısınız.


4

Dosya, paylaşılan bir klasör gibi uzak bir klasördeyse bu hata atılabilir. Veritabanını yerel bir dizine değiştirdim ve mükemmel çalıştı.


3

Ben uygulama içinde böyle bir sorun var, hangi SQLite erişim 2 bağlantı - bir salt okunur ve yazma ve okuma için ikinci oldu. Bu, salt okunur bağlantının ikinci bağlantıdan yazılmasını engellediği anlaşılıyor. Son olarak, hazırlanan ifadelerin kullanımdan sonra HEMEN bitirilmesi veya en azından sıfırlanması gerektiği ortaya çıkmaktadır. Hazırlanan ifade açılana kadar veritabanına yazılması engellendi.

ÇAĞRI UNUTMAYIN:

sqlite_reset(xxx);

veya

sqlite_finalize(xxx);

3

INDEX'ing gibi bazı işlevler çok uzun zaman alabilir - ve çalışırken tüm veritabanını kilitler. Böyle durumlarda günlük dosyasını bile kullanamayabilir!

Bu nedenle, veritabanınızın kilitli olup olmadığını kontrol etmenin en iyi / tek yolu, bir işlem ETKİN olarak ona yazdığı için (ve böylece işlemi tamamlanana kadar cehennemi yalnız bırakmanız gerekir) dosyayı iki kez md5 (veya bazı sistemlerde md5sum) . Farklı bir sağlama toplamı alırsanız, veritabanı yazılır ve gerçekten gerçekten -9 bu işlemi öldürmek istemezsiniz, çünkü eğer kolayca bozuk bir tablo / veritabanı ile sonuçlanabilir.

Tekrar edeceğim, çünkü önemli - çözüm kilitleme programını bulmak ve öldürmek DEĞİL - veritabanının iyi bir nedenden dolayı yazma kilidine sahip olup olmadığını bulmak ve oradan gitmek. Bazen doğru çözüm sadece bir kahve molasıdır.

Bu kilitli ama yazılmamış olan durumu yaratmanın tek yolu, programınızın çalışmasıdır BEGIN EXCLUSIVE, çünkü bazı tablo değişiklikleri yapmak veya bir şey yapmak isterse, o zaman neden daha ENDsonra hiç göndermezse ve süreç asla sona ermez . Karşılaşılan her üç koşul da uygun şekilde yazılmış herhangi bir kodda pek olası değildir ve birisi kilitleme işlemini -9'u öldürmek istediğinde 100'den 99'u gibi, kilitleme işlemi aslında veritabanınızı iyi bir nedenden dolayı kilitler. Programcılar, BEGIN EXCLUSIVEgerçekten gerekmedikçe durumu eklemezler, çünkü eşzamanlılığı önler ve kullanıcı şikayetlerini artırır. SQLite sadece gerçekten ihtiyaç duyduğunda ekler (indeksleme gibi).

Son olarak, birkaç yanıtın belirttiği gibi dosyanın İÇİNDE 'kilitli' durumu yoktur - İşletim Sisteminin çekirdeğinde bulunur. BEGIN EXCLUSIVEİşletim sisteminden kilit işlemi istenen dosyaya yerleştirilir. Özel işleminiz çökse bile, işletim sisteminiz dosya kilidini korumayı sürdürüp sürdürmeyeceğini anlayabilir! Kilitli bir veritabanı ile sonuçlanmak mümkün değildir, ancak hiçbir işlem aktif olarak kilitlemez !! Hangi işlemin dosyayı kilitlediğini görmek söz konusu olduğunda, kaynaştırıcıdan ziyade lsof kullanmak daha iyidir (bu nedeninin iyi bir gösterisidir: /unix/94316/fuser-vs-lsof- kullanımda dosyaları kontrol etmek için ). Alternatif olarak DTrace (OSX) varsa dosyada iosnoop kullanabilirsiniz.


2

Benim de benzer bir şey yaşadım - web uygulamam veritabanından okuyabildi, ancak herhangi bir ekleme veya güncelleme yapamadı. Apache'nin yeniden başlatılması sorunu en azından geçici olarak çözdü.

Bununla birlikte, temel nedeni takip edebilmek güzel olurdu.


2

Linux ortamımdaki lsof komutu, dosyayı açık tutarak bir işlemin asılı olduğunu anlamama yardımcı oldu.
Süreci öldürdü ve sorun çözüldü.



2

Bir veritabanının iç sorunu olmalı ...
Benim için "SQLite yöneticisi" ile veritabanına göz atmaya çalıştıktan sonra tezahür etti ...
Yani, başka bir işlem bulamazsanız veritabanına bağlanır ve düzeltemezsiniz, şu radikal çözümü deneyin:

  1. Tablolarınızı dışa aktarmayı sağlayın (Firefox'ta "SQLite yöneticisi" ni kullanabilirsiniz)
  2. Taşıma veritabanı düzeninizi değiştirirse başarısız olan son taşıma işlemini silin
  3. "Database.sqlite" dosyanızı yeniden adlandırın
  4. Yeni bir çalışma veritabanı oluşturmak için "rake db: migrate" komutunu yürütün
  5. Tablonun içe aktarılması için veritabanına doğru izinlerin verilmesini sağlayın
  6. Yedeklenmiş tablolarınızı içe aktarın
  7. Yeni taşıma işlemini yazın
  8. " rake db:migrate" İle çalıştır

1

Aynı sorunu bir terminal oturumundan Python komut dosyalarını çalıştıran Mac OS X 10.5.7'de gördüm. Komut dosyalarını durdurmuş ve terminal penceresi komut isteminde oturmuş olsa da, bir dahaki sefere bu hatayı verecektir. Çözüm, terminal penceresini kapatmak ve tekrar açmaktı. Bana bir anlam ifade etmiyor, ama işe yaradı.


1

Aynı hatayla karşılaştım. 5 minets google-ing sonra ben bir kabuk cadı db kullandığını kapatmadım bulundu. Sadece kapatın ve tekrar deneyin;)


1

Ben de aynı problemi yaşadım. Görünüşe göre geri alma işlevi, db dosyasının db dosyasıyla aynı olan ancak en son değişiklik olmadan günlüğe yazdığını söylüyor. Aşağıdaki kodumda bu uyguladım ve o zamandan beri iyi çalışıyor, oysa benim kod sadece veritabanı kilitli kaldı gibi döngü içinde sıkışmış olur.

Bu yardımcı olur umarım

python kodum

##############
#### 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

Bu istisnayı almanın yaygın bir nedeni, bir okuma işlemi için kaynakları tutarken bir yazma işlemi yapmaya çalışmanızdır. Örneğin, bir tablodan SEÇ, sonra da ResultSet'inizi kapatmadan seçtiğiniz bir şeyi GÜNCELLEMEYE çalışırsanız.


1

Ben görünüyor ki, hem çok dişli bir uygulama hataları "Veritabanı kilitli" başlamıştı SQLITE_BUSY sonuç kodu ve ben ayarı ile çözüldü sqlite3_busy_timeout uygun uzun 30000 gibi bir şey.

(Bir yan notta, 7 yaşındaki bir soruda kimse bunu şimdiye kadar bulamadı! SQLite gerçekten tuhaf ve şaşırtıcı bir proje ...)


1

Yeniden başlatma seçeneğine gitmeden önce, sqlite veritabanının kullanıcısını bulabileceğinizi görmek önemlidir.

Linux'ta fuserbu amaçla kullanılabilir:

$ fuser database.db

$ fuser database.db-journal

Benim durumumda şu yanıtı aldım:

philip    3556  4700  0 10:24 pts/3    00:00:01 /usr/bin/python manage.py shell

Hangi veritabanı kullanarak pid 3556 (manage.py) ile başka bir Python programı olduğunu gösterdi.


1

Eski bir soru, çok sayıda cevabı olan, yukarıdaki cevapları okurken izlediğim adımlar burada, ancak benim durumumda sorun ciflerin kaynak paylaşımından kaynaklanıyor. Bu vaka daha önce bildirilmedi, umarım birine yardımcı olur.

  • Java kodunuzda açık bağlantı kalmadığını kontrol edin.
  • Başka hiçbir işlemin SQLite db dosyanızı lsof ile kullanmadığını kontrol edin.
  • Çalışan jvm işleminizin kullanıcı sahibinin dosya üzerinde r / w izinleri olduğunu kontrol edin.
  • Bağlantı açıklığındaki kilit modunu

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

SQLite db dosyanızı bir NFS paylaşımlı klasörü üzerinde kullanıyorsanız, SQLite SSS'nin bu noktasını kontrol edin ve burada açıklandığı gibi kilitlerden kaçındığınızdan emin olmak için montaj yapılandırma seçeneklerinizi gözden geçirin :

//myserver /mymount cifs username=*****,password=*****,iocharset=utf8,sec=ntlm,file,nolock,file_mode=0700,dir_mode=0700,uid=0500,gid=0500 0 0

1

Bu hatayı burada açıklananlardan biraz farklı bir senaryoda aldım.

SQLite veritabanı 3 sunucu tarafından paylaşılan bir NFS dosya sistemine dayanıyordu. Sunucuların 2'sinde veritabanında sorguları başarıyla çalıştırabildim, üçüncüsünde "veritabanı kilitli" mesajını aldığımı düşündüm.

Bu 3. makine ile ilgili bir şey, üzerinde boş alan kalmamasıydı /var. Everytime ben bu dosya sisteminde bulunan HERHANGİ bir SQLite veritabanında bir sorgu çalıştırmak için çalıştı "veritabanı kilitli" mesajı ve ayrıca günlükleri üzerinde bu hata var:

Ağu 8 10:33:38 server01 çekirdek: lockd: izlenemiyor 172.22.84.87

Ve bu da:

Ağu 8 10:33:38 server01 rpc.statd [7430]: Eklenemedi: yazı /var/lib/nfs/statd/sm/other.server.name.com: Cihazda boşluk kalmadı 8 Ağu 33: 38 server01 rpc.statd [7430]: SM_MON için 172.22.84.87 için STAT_FAIL - sunucu01

Uzay durumu ele alındıktan sonra her şey normale döndü.


1

Eğer kilidini çalışıyorsanız Chrome veritabanını için SQLite ile görüntülemek , o zaman sadece Chrome'u kapatın.

pencereler

%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

Mac

~/Library/Application Support/Google/Chrome/Default/Web Data

0

Önceki yorumlarınızdan bir dergi dosyasının olduğunu söylediniz.

Bu, işlemi açtığınız ve (ÖZEL?) İşlem yaptığınız ve henüz verileri işlemediğiniz anlamına gelebilir. Programınız ya da başka bir süreç -Geriyeti geride mi bıraktı ??

Sqlite işleminin yeniden başlatılması günlük dosyasına bakar ve taahhüt edilmeyen eylemleri temizler ve -journal dosyasını kaldırır.


0

Seun Osewa'nın dediği gibi, bazen bir zombi süreci, mümkün olduğunu düşünmeseniz bile, terminalde kilitli bir kilitle oturur. Komut dosyanız çalışıyor, çöküyor ve isteme geri dönüyorsunuz, ancak bir yerde bir kütüphane çağrısı tarafından ortaya çıkan bir zombi işlemi var ve bu işlemin kilidi var.

Bulunduğunuz terminalin kapatılması (OSX'te) işe yarayabilir. Yeniden başlatma işe yarayacaktır. Hiçbir şey yapmayan "python" süreçleri arayabilir ve onları öldürebilirsiniz.


0

bunu deneyebilirsiniz: .timeout 100zaman aşımı süresini ayarlamak için. Komut satırında ne olduğunu bilmiyorum ama bunu yaptığımda C # .Net: "UPDATE table-name SET column-name = value;"Veritabanı kilitli olsun ama bu "UPDATE table-name SET column-name = value"iyi gidiyor.

Eklediğinizde gibi görünüyor;, sqlite daha fazla komut arayacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.