Bagaimana cara membuka kunci basis data SQLite?

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

Bagaimana cara membuka kunci basis data sehingga ini akan berfungsi?

irama
sumber
Mungkin ada proses lain mengakses file database - apakah Anda memeriksa lsof?
ada
Saya memiliki masalah yang sama, masalahnya ada di antivirus ketika saya menonaktifkannya aplikasi saya berfungsi dengan baik, tetapi ketika saya mengaktifkannya saya menemukan beberapa kesalahan "database terkunci", saya harap itu akan membantu Anda.
user8510915

Jawaban:

267

Di windows Anda dapat mencoba program ini http://www.nirsoft.net/utils/opened_files_view.html untuk mengetahui proses penanganan file db. Coba tutup program itu untuk membuka kunci basis data

Di Linux dan macOS Anda dapat melakukan sesuatu yang serupa, misalnya, jika file Anda terkunci pengembangan.db:

$ fuser development.db

Perintah ini akan menunjukkan proses apa yang mengunci file:

> development.db: 5430

Bunuh saja prosesnya ...

bunuh -9 5430

... Dan basis data Anda akan dibuka.

bukan asli
sumber
19
... dengan peringatan jelas bahwa Anda perlu tahu apa yang Anda lakukan. Jika ini adalah proses yang tidak penting maka killharus baik-baik saja, tetapi Anda harus berhati-hati untuk membunuhnya dengan benar, dan kill -9mungkin salah dan / atau berlebihan. Jika prosesnya terhenti dan tidak akan mati, terkadang Anda memang membutuhkannya kill -9. Tetapi Anda tidak ingin pergi dan mematikan pekerjaan produksi utama hanya agar Anda dapat melaporkan bahwa basis data tidak lagi terkunci!
tripleee
Solusi yang lebih sederhana adalah dengan hanya me-restart komputer Anda.
chacham15
7
@ chacham15: Anda berasumsi bahwa basis data ada di komputer "saya", dan Anda mengabaikan kemungkinan banyak proses penting yang berjalan di komputer yang sama dengan yang ada di basis data yang terkunci. Solusi "sederhana" tidak pernah sesederhana itu;)
tzot
1
@KyleCarlson - sqlite dan mysql pada dasarnya berbeda dalam aspek itu. Tidak ada yang salah dengan SQLite-db-browser.
Berry Tsakala
6
Solusi ini mengasumsikan bahwa ada proses mengunci file. Ada kemungkinan bahwa proses macet meninggalkan file SQLite dalam keadaan tidak dapat digunakan. Dalam hal ini, lihat jawaban saya.
robert
90

Saya menyebabkan sqlite db menjadi terkunci dengan menabrak aplikasi saat menulis. Inilah cara saya memperbaikinya:

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

Diambil dari: http://random.kakaopor.hu/how-to-repair-an-sqlite-database

robert
sumber
4
sqlite3:sqlite> .dump PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; /**** ERROR: (5) database is locked *****/ ROLLBACK; -- due to errors
woky
Tidak bekerja untukFOREIGN KEY constraint failed (RELEASE RESTOREPOINT)
gies0r
52

Halaman DatabaseIsLocked yang tercantum di bawah tidak lagi tersedia. Halaman Penguncian File dan Konkurensi menjelaskan perubahan terkait penguncian file yang diperkenalkan di v3 dan mungkin bermanfaat bagi pembaca di masa mendatang. https://www.sqlite.org/lockingv3.html

Halaman DatabaseIsLocked SQLiki wiki menawarkan penjelasan yang baik tentang pesan kesalahan ini. Ini menyatakan, sebagian, bahwa sumber pertengkaran adalah internal (untuk proses memancarkan kesalahan).

Apa yang tidak dijelaskan halaman ini adalah bagaimana SQLite memutuskan bahwa sesuatu dalam proses Anda memegang kunci dan kondisi apa yang dapat mengarah pada false positive.

konverter42
sumber
2
Masalahnya adalah halaman tersebut salah atau kedaluwarsa: Saya memiliki proses yang tidak melakukan apa-apa selain satu INSERT yang mendapatkan pesan yang dikunci: tidak mungkin proses ini menyebabkan kunci. Masalahnya adalah dalam proses lain berbicara dengan DB yang sama.
Dan Jameson
4
@ converter42 Tautan rusak.
Ole Tange
32

Menghapus file -jurnal terdengar seperti ide yang buruk. Itu ada di sana untuk memungkinkan sqlite untuk memutar kembali database ke keadaan yang konsisten setelah crash. Jika Anda menghapusnya saat database dalam keadaan tidak konsisten, maka Anda pergi dengan database yang rusak. Mengutip halaman dari situs sqlite :

Jika crash atau kehilangan daya memang terjadi dan jurnal panas dibiarkan di disk, sangat penting bahwa file database asli dan jurnal panas tetap di disk dengan nama asli mereka sampai file database dibuka oleh proses SQLite lain dan digulung kembali . [...]

Kami menduga bahwa mode kegagalan umum untuk pemulihan SQLite terjadi seperti ini: Terjadi kegagalan daya. Setelah daya pulih, pengguna atau administrator sistem yang bermaksud baik mulai mencari-cari kerusakan pada disk. Mereka melihat file database mereka bernama "important.data". File ini mungkin tidak asing bagi mereka. Tetapi setelah crash, ada juga jurnal panas bernama "important.data-journal". Pengguna kemudian menghapus jurnal panas, berpikir bahwa mereka membantu membersihkan sistem. Kami tahu tidak ada cara untuk mencegah hal ini selain dari pendidikan pengguna.

Kembalikan seharusnya terjadi secara otomatis saat berikutnya database dibuka, tetapi itu akan gagal jika proses tidak dapat mengunci database. Seperti yang dikatakan orang lain, salah satu alasan yang memungkinkan untuk ini adalah bahwa proses lain saat ini terbuka. Kemungkinan lain adalah kunci NFS basi, jika database pada volume NFS. Dalam hal ini, solusinya adalah mengganti file database dengan salinan baru yang tidak terkunci pada server NFS (mv database.db original.db; cp original.db database.db). Perhatikan bahwa FAQ sqlite merekomendasikan kehati-hatian tentang akses bersamaan ke database pada volume NFS, karena implementasi penguncian file NFS yang bermasalah.

Saya tidak bisa menjelaskan mengapa menghapus file -jurnal akan membiarkan Anda mengunci basis data yang sebelumnya tidak bisa Anda lakukan. Apakah itu dapat direproduksi?

Ngomong-ngomong, keberadaan file -jurnal tidak selalu berarti bahwa ada crash atau ada perubahan yang harus dibatalkan. Sqlite memiliki beberapa mode jurnal yang berbeda, dan dalam mode PERSIST atau TRUNCATE ia meninggalkan file -jurnal pada tempatnya, dan mengubah konten untuk menunjukkan apakah ada transaksi parsial untuk memutar kembali.

Harun
sumber
23

Jika Anda ingin menghapus kesalahan "basis data dikunci" maka ikuti langkah-langkah ini:

  1. Salin file database Anda ke beberapa lokasi lain.
  2. Ganti database dengan database yang disalin. Ini akan mengubah semua proses yang mengakses file database Anda.
vinayak jadi
sumber
2
Saya mencoba 'fuser <DB>' seperti dijelaskan di atas, tetapi tidak berhasil. Langkah sederhana ini berhasil untuk saya.
Jackie Yeh
Dalam kasus saya, saya juga harus me-restart Notebook Jupyter saya.
Victor
15

Jika suatu proses memiliki kunci pada DB SQLite dan crash, DB tetap terkunci secara permanen. Itulah masalahnya. Bukannya beberapa proses lain memiliki kunci.


sumber
48
jadi bagaimana cara membuka kunci db?
Erik Kaplun
4
Ini tidak benar. Kunci dikelola oleh OS. Baca jawabannya di bawah ini.
JJ
13

file db SQLite hanyalah file, jadi langkah pertama adalah memastikan itu bukan hanya-baca. Hal lain yang harus dilakukan adalah memastikan bahwa Anda tidak memiliki semacam penampil DB GUI SQLite dengan DB terbuka. Anda bisa membuka DB di shell lain, atau kode Anda mungkin memiliki DB terbuka. Biasanya Anda akan melihat ini jika utas yang berbeda, atau aplikasi seperti SQLite Database Browser memiliki DB terbuka untuk ditulis.

Pelit Panas
sumber
4
Dalam pengalaman saya, SQLite Database Browser (SDB) secara reproduktif mengunci basis data jika Anda mengedit data dengannya tetapi kemudian tidak menyimpannya di SDB. Jika Anda menyimpannya, itu melepaskan kunci.
Chelonian
Saya bisa menyisipkan tetapi saya tidak bisa menghapus.
Wennie
10

Saya punya masalah ini sekarang, menggunakan database SQLite pada server jauh, disimpan pada mount NFS. SQLite tidak dapat memperoleh kunci setelah sesi shell remote yang saya gunakan mengalami crash ketika database terbuka.

Resep untuk pemulihan yang disarankan di atas tidak bekerja untuk saya (termasuk ide untuk memindahkan terlebih dahulu dan kemudian menyalin database kembali). Tetapi setelah menyalinnya ke sistem non-NFS, database menjadi dapat digunakan dan bukan data yang tampaknya telah hilang.

jogojapan
sumber
9

Kunci saya disebabkan oleh sistem crash dan bukan oleh proses gantung. Untuk mengatasi ini saya cukup mengganti nama file kemudian menyalinnya kembali ke nama dan lokasi aslinya.

Menggunakan shell linux yang akan ...

mv mydata.db temp.db
cp temp.db mydata.db
Ben L
sumber
solusi yang sangat mudah, menyelesaikan masalah saya dari basis data yang terkunci pada drive jaringan.
Maverick2805
7

Saya menambahkan " Pooling=true" ke string koneksi dan itu berhasil.

pengguna1900210
sumber
4

Saya menemukan dokumentasi berbagai negara mengunci SQLite sangat membantu. Michael, jika Anda dapat melakukan membaca tetapi tidak dapat melakukan menulis ke database, itu berarti bahwa suatu proses telah mendapatkan kunci RESERVED pada database Anda tetapi belum menjalankan penulisan. Jika Anda menggunakan SQLite3, ada kunci baru yang disebut PENDING di mana tidak ada lagi proses yang diizinkan untuk menyambungkan tetapi koneksi yang ada dapat tetap melakukan pembacaan, jadi jika ini masalahnya, Anda harus melihatnya.

Kyle Cronin
sumber
4

Kesalahan ini dapat terjadi jika file ada di folder jarak jauh, seperti folder bersama. Saya mengubah database ke direktori lokal dan itu bekerja dengan sempurna.

Zequez
sumber
3

Saya memiliki masalah seperti itu di dalam aplikasi, yang mengakses SQLite dari 2 koneksi - satu hanya-baca dan yang kedua untuk menulis dan membaca. Sepertinya koneksi read-only memblokir penulisan dari koneksi kedua. Akhirnya, ternyata diperlukan untuk menyelesaikan atau, setidaknya, mengatur ulang pernyataan yang disiapkan SEGERA setelah digunakan. Sampai pernyataan yang disiapkan dibuka, itu menyebabkan database diblokir untuk penulisan.

JANGAN LUPA PANGGILAN:

sqlite_reset(xxx);

atau

sqlite_finalize(xxx);
Mike Keskinov
sumber
3

Beberapa fungsi, seperti INDEX'ing, dapat memakan waktu sangat lama - dan mengunci seluruh basis data saat dijalankan. Dalam hal seperti itu, bahkan mungkin tidak menggunakan file jurnal!

Jadi cara terbaik / satu-satunya untuk memeriksa apakah basis data Anda terkunci karena suatu proses AKTIF menulisnya (dan dengan demikian Anda harus membiarkannya sendiri sampai selesai operasinya) adalah dengan md5 (atau md5sum pada beberapa sistem) file dua kali . Jika Anda mendapatkan checksum yang berbeda, database sedang ditulis, dan Anda benar-benar BENAR-BENAR tidak ingin membunuh -9 proses itu karena Anda dapat dengan mudah berakhir dengan tabel / database yang korup jika Anda melakukannya.

Saya akan mengulangi, karena ini penting - solusinya adalah TIDAK menemukan program penguncian dan membunuhnya - itu untuk menemukan apakah database memiliki kunci tulis untuk alasan yang baik, dan pergi dari sana. Terkadang solusi yang tepat adalah hanya coffee break.

Satu-satunya cara untuk membuat situasi terkunci-tapi-tidak-sedang-ditulis-ke ini adalah jika program Anda berjalan BEGIN EXCLUSIVE, karena ingin melakukan beberapa perubahan tabel atau sesuatu, maka untuk alasan apa pun tidak pernah mengirim ENDsesudahnya, dan proses tidak pernah berakhir . Ketiga kondisi yang dipenuhi sangat tidak mungkin dalam kode yang ditulis dengan benar, dan dengan demikian 99 kali dari 100 ketika seseorang ingin membunuh -9 proses penguncian mereka, proses penguncian sebenarnya mengunci database Anda untuk alasan yang baik. Pemrogram biasanya tidak menambahkan BEGIN EXCLUSIVEkondisi kecuali mereka benar-benar perlu, karena mencegah konkurensi dan meningkatkan keluhan pengguna. SQLite sendiri hanya menambahkannya ketika benar-benar perlu (seperti saat pengindeksan).

Akhirnya, status 'terkunci' tidak ada DI DALAM file seperti yang telah dijawab beberapa jawaban - ia berada di kernel Sistem Operasi. Proses yang dijalankan BEGIN EXCLUSIVEtelah meminta dari OS kunci ditempatkan pada file. Bahkan jika proses eksklusif Anda macet, OS Anda akan dapat mengetahui apakah harus menjaga kunci file atau tidak !! Tidak mungkin berakhir dengan basis data yang terkunci tetapi tidak ada proses yang secara aktif menguncinya !! Ketika datang untuk melihat proses mana yang mengunci file, biasanya lebih baik menggunakan lsof daripada fuser (ini adalah demonstrasi yang bagus tentang mengapa: /unix/94316/fuser-vs-lsof- to-check-files-in-use ). Atau jika Anda memiliki DTrace (OSX), Anda dapat menggunakan iosnoop pada file.

JJ
sumber
2

Saya baru saja mengalami hal serupa pada saya - aplikasi web saya dapat membaca dari database, tetapi tidak dapat melakukan sisipan atau pembaruan. Reboot Apache memecahkan masalah setidaknya untuk sementara waktu.

Akan lebih baik, bagaimanapun, untuk dapat melacak penyebab dasarnya.

Michael Cox
sumber
2

Perintah lsof di lingkungan Linux saya membantu saya mengetahui bahwa ada proses yang menggantung agar file tetap terbuka.
Membunuh proses dan masalah terpecahkan.

PinkSheep
sumber
2

Seharusnya menjadi masalah internal basis data ...
Bagi saya itu telah dimanifestasikan setelah mencoba menelusuri basis data dengan "SQLite manager" ...
Jadi, jika Anda tidak dapat menemukan proses lain terhubung ke basis data dan Anda tidak dapat memperbaikinya, coba saja solusi radikal ini:

  1. Berikan untuk mengekspor tabel Anda (Anda dapat menggunakan "SQLite manager" di Firefox)
  2. Jika migrasi mengubah skema database Anda, hapus migrasi yang gagal terakhir
  3. Ganti nama file "database.sqlite" Anda
  4. Jalankan "rake db: migrate" untuk membuat database yang berfungsi
  5. Berikan untuk memberikan izin yang tepat ke database untuk mengimpor tabel
  6. Impor tabel cadangan Anda
  7. Tulis migrasi baru
  8. Jalankan dengan " rake db:migrate"
Davide Ganz
sumber
1

Saya mengalami masalah yang sama pada Mac OS X 10.5.7 menjalankan skrip Python dari sesi terminal. Meskipun saya telah menghentikan skrip dan jendela terminal duduk di command prompt, itu akan memberikan kesalahan ini saat dijalankan berikutnya. Solusinya adalah dengan menutup jendela terminal dan kemudian membukanya lagi. Tidak masuk akal bagi saya, tetapi itu berhasil.

Shawn Swaner
sumber
1

Saya baru saja mengalami kesalahan yang sama. Setelah 5 menit google-ing saya menemukan bahwa saya tidak menutup satu penyihir shell menggunakan db. Tutup saja dan coba lagi;)

Mengalir
sumber
1

Saya memiliki masalah yang sama. Rupanya fungsi rollback tampaknya menimpa file db dengan jurnal yang sama dengan file db tetapi tanpa perubahan terbaru. Saya sudah menerapkan ini dalam kode saya di bawah ini dan sudah berfungsi dengan baik sejak saat itu, sedangkan sebelum kode saya hanya akan terjebak dalam loop karena database tetap terkunci.

Semoga ini membantu

kode python saya

##############
#### 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 )
Jay
sumber
1

Salah satu alasan umum untuk mendapatkan pengecualian ini adalah ketika Anda mencoba melakukan operasi tulis sambil tetap memegang sumber daya untuk operasi baca. Misalnya, jika Anda MEMILIH dari tabel, dan kemudian mencoba untuk MEMPERBARUI sesuatu yang telah Anda pilih tanpa menutup ResultSet Anda terlebih dahulu.

Martin Carney
sumber
1

Saya mengalami "database terkunci" kesalahan dalam aplikasi multi-threaded juga, yang tampaknya menjadi kode hasil SQLITE_BUSY , dan saya menyelesaikannya dengan menetapkan sqlite3_busy_timeout ke sesuatu yang sesuai dengan panjang seperti 30000.

(Di samping catatan, betapa aneh bahwa pada pertanyaan berusia 7 tahun tidak ada yang tahu ini! SQLite benar-benar adalah proyek yang aneh dan menakjubkan ...)

Stijn Sanders
sumber
1

Sebelum turun opsi reboot, ada baiknya untuk melihat apakah Anda dapat menemukan pengguna dari database sqlite.

Di Linux, seseorang dapat menggunakan fuseruntuk tujuan ini:

$ fuser database.db

$ fuser database.db-journal

Dalam kasus saya, saya mendapat respons berikut:

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

Yang menunjukkan bahwa saya punya program Python lain dengan pid 3556 (manage.py) menggunakan database.

Philip Clarke
sumber
1

Sebuah pertanyaan lama, dengan banyak jawaban, inilah langkah-langkah yang saya ikuti baru-baru ini membaca jawaban di atas, tetapi dalam kasus saya masalahnya adalah karena berbagi sumber daya cifs. Kasus ini tidak dilaporkan sebelumnya, jadi semoga membantu seseorang.

  • Periksa tidak ada koneksi yang dibiarkan terbuka di kode java Anda.
  • Periksa tidak ada proses lain yang menggunakan file db SQLite Anda dengan lsof.
  • Periksa pemilik pengguna yang menjalankan proses jvm Anda memiliki r / w izin atas file tersebut.
  • Cobalah untuk memaksa mode kunci pada pembukaan koneksi dengan

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

Jika Anda menggunakan file db SQLite Anda di folder bersama NFS, periksa titik faq SQLite ini, dan tinjau opsi konfigurasi pemasangan Anda untuk memastikan Anda menghindari kunci, seperti dijelaskan di sini :

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

Saya mendapatkan kesalahan ini dalam skenario yang sedikit berbeda dari yang dijelaskan di sini.

Basis data SQLite bersandar pada sistem file NFS yang dibagikan oleh 3 server. Pada 2 server saya berhasil menjalankan query pada database, pada pemikiran ketiga saya mendapatkan pesan "database is locked".

Masalahnya dengan mesin ke-3 ini adalah tidak ada ruang tersisa /var. Setiap kali saya mencoba menjalankan kueri di database SQL APAPUN yang terletak di sistem file ini, saya menerima pesan "database is locked" dan juga kesalahan ini di atas log:

8 Agustus 10:33:38 server01 kernel: lockd: tidak dapat memantau 172.22.84.87

Dan yang ini juga:

8 Agustus 10:33:38 server01 rpc.statd [7430]: Gagal menyisipkan: menulis /var/lib/nfs/statd/sm/other.server.name.com: Tidak ada ruang tersisa di perangkat 8 Agustus 10:33: 38 server01 rpc.statd [7430]: STAT_FAIL ke server01 untuk SM_MON dari 172.22.84.87

Setelah situasi ruang ditangani semuanya kembali normal.

ederribeiro
sumber
1

Jika Anda mencoba membuka kunci basis data Chrome untuk melihatnya dengan SQLite , maka matikan saja 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

Mac

~/Library/Application Support/Google/Chrome/Default/Web Data
Bob Stein
sumber
0

Dari komentar Anda sebelumnya, Anda mengatakan file jurnal ada.

Ini bisa berarti bahwa Anda telah membuka dan (EKSKLUSIF?) Transaksi dan belum melakukan data. Apakah program Anda atau proses lain meninggalkan -jurnal?

Restart proses sqlite akan melihat file jurnal dan membersihkan setiap tindakan yang tidak berkomitmen dan menghapus file -journal


sumber
0

Seperti dikatakan Seun Osewa, kadang-kadang proses zombie akan duduk di terminal dengan kunci yang diperoleh, bahkan jika Anda tidak berpikir itu mungkin. Script Anda berjalan, macet, dan Anda kembali ke prompt, tetapi ada proses zombie yang muncul di suatu tempat oleh panggilan perpustakaan, dan proses itu memiliki kunci.

Menutup terminal tempat Anda berada (pada OSX) mungkin berhasil. Mulai ulang akan berhasil. Anda bisa mencari proses "python" (misalnya) yang tidak melakukan apa-apa, dan membunuh mereka.

sayu
sumber
0

Anda dapat mencoba ini: .timeout 100untuk mengatur batas waktu. Saya tidak tahu apa yang terjadi di baris perintah tetapi di C # .Net ketika saya melakukan ini: "UPDATE table-name SET column-name = value;"Saya mendapatkan Basis Data terkunci tetapi ini "UPDATE table-name SET column-name = value"berjalan dengan baik.

Sepertinya ketika Anda menambahkan;, sqlite akan mencari perintah lebih lanjut.

Dzung Nguyen
sumber