質問
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
プロセスを強制終了するだけです...
kill -9 5430
...そしてデータベースのロックが解除されます。
他のヒント
書き込み中にアプリをクラッシュさせることで、sqlite dbをロックしました。修正方法は次のとおりです。
echo ".dump" | sqlite old.db | sqlite new.db
取得元: http://random.kakaopor.hu/how-to-repair- an-sqlite-database
以下にリストされているDatabaseIsLockedページは使用できなくなりました。ファイルのロックと同時実行のページでは、v3で導入されたファイルロックに関連する変更について説明しており、将来の読者に役立つ可能性があります。 https://www.sqlite.org/lockingv3.html
SQLite wiki DatabaseIsLocked ページは、このエラーメッセージの適切な説明を提供します。 。競合の原因は内部的なものである(エラーを出力しているプロセスの)ことを部分的に述べています。
このページで説明されていないのは、プロセス内の何かがロックを保持しているとSQLiteが判断する方法と、どのような条件が誤検知につながる可能性があるかです。
-journalファイルの削除は、ひどいアイデアのように聞こえます。クラッシュ後、sqliteがデータベースを一貫した状態にロールバックできるようにするためにあります。データベースが一貫性のない状態にある間に削除すると、破損したデータベースが残ります。 sqliteサイトからページを引用:
クラッシュまたは停電が発生し、ホットジャーナルがディスク上に残っている場合、データベースファイルが別のSQLiteプロセスによって開かれるまで、元のデータベースファイルとホットジャーナルが元の名前でディスク上に残っていることが不可欠ですそしてロールバック。 [...]
SQLiteリカバリの一般的な障害モードは、次のように発生すると思われます。電源障害が発生します。電源が回復した後、善意のユーザーまたはシステム管理者は、損傷がないかディスクを調べ始めます。彼らは" important.data"という名前のデータベースファイルを見ます。このファイルはおそらくおなじみのものです。しかし、クラッシュ後、「important.data-journal」という名前のホットジャーナルもあります。ユーザーはホットジャーナルを削除し、システムのクリーンアップに役立っていると考えます。ユーザー教育以外にこれを防ぐ方法はありません。
ロールバックは、次回データベースを開いたときに自動的に発生するはずですが、プロセスがデータベースをロックできない場合は失敗します。他の人が言ったように、これの1つの考えられる理由は、別のプロセスが現在それを開いていることです。別の可能性は、データベースがNFSボリューム上にある場合、古いNFSロックです。その場合の回避策は、NFSサーバーでロックされていない新しいコピー(mv database.db original.db; cp original.db database.db)でデータベースファイルを置き換えることです。 NFSファイルロックのバグのある実装のため、sqlite FAQはNFSボリューム上のデータベースへの同時アクセスに関する注意を推奨していることに注意してください。
-journalファイルを削除すると、以前はできなかったデータベースをロックできる理由を説明できません。再現可能ですか?
ところで、-journalファイルの存在は、必ずしもクラッシュがあったことや、ロールバックする変更があることを意味するわけではありません。 Sqliteにはいくつかの異なるジャーナルモードがあり、PERSISTモードまたはTRUNCATEモードでは、-journalファイルを常に所定の場所に残し、内容を変更して、ロールバックする部分的なトランザクションがあるかどうかを示します。
「データベースがロックされています」を削除する場合エラーが発生した場合は、次の手順に従ってください:
- データベースファイルを他の場所にコピーします。
- データベースをコピーしたデータベースに置き換えます。これにより、データベースファイルにアクセスしていたすべてのプロセスが逆参照されます。
プロセスがSQLite DBをロックしてクラッシュした場合、DBは永続的にロックされたままになります。それが問題です。他のプロセスがロックしているわけではありません。
SQLite dbファイルは単なるファイルであるため、最初のステップは読み取り専用でないことを確認することです。もう1つやることは、DBを開いた状態でGUI SQLite DBビューアーを使用しないようにすることです。 DBを別のシェルで開くことも、コードでDBを開くこともできます。通常、別のスレッド、またはSQLite Database BrowserなどのアプリケーションでDBが書き込み用に開かれている場合に表示されます。
NFSマウントに保存されたリモートサーバー上のSQLiteデータベースを使用して、この問題が発生しました。データベースを開いているときに、使用したリモートシェルセッションがクラッシュした後、SQLiteはロックを取得できませんでした。
上記で提案したリカバリのレシピは、私にとってはうまくいきませんでした(最初にデータベースを移動してからコピーするというアイデアを含む)。しかし、NFS以外のシステムにコピーした後、データベースは使用可能になり、データは失われたようには見えません。
ロックは、プロセスのハングではなく、システムのクラッシュが原因で発生しました。これを解決するには、単にファイルの名前を変更してから、元の名前と場所にコピーして戻しました。
Linuxシェルを使用すると...
mv mydata.db temp.db
cp temp.db mydata.db
" Pooling = true
"を追加しました接続文字列に、それが働いた。
SQLiteのロックのさまざまな状態に関するドキュメントが非常に役立つことがわかりました。マイケル、読み取りはできるがデータベースへの書き込みはできないということは、プロセスがデータベースのRESERVEDロックを取得したが、まだ書き込みを実行していないことを意味します。 SQLite3を使用している場合、PENDINGと呼ばれる新しいロックがあり、これ以上のプロセスは接続できませんが、既存の接続は読み取りを実行することができます。
このエラーは、ファイルが共有フォルダーなどのリモートフォルダーにある場合にスローされる可能性があります。データベースをローカルディレクトリに変更しましたが、完全に機能しました。
2つの接続からSQLiteにアクセスするアプリ内にこのような問題があります。1つは読み取り専用で、もう1つは書き込みと読み取り用です。読み取り専用接続が2番目の接続からの書き込みをブロックしたようです。最後に、使用後すぐに準備済みステートメントを確定するか、少なくともリセットする必要があります。準備されたステートメントが開かれるまで、データベースへの書き込みがブロックされました。
電話を忘れないでください:
sqlite_reset(xxx);
または
sqlite_finalize(xxx);
INDEX'ingなどの一部の関数は非常に長い時間がかかる場合があり、実行中にデータベース全体をロックします。そのような例では、ジャーナルファイルさえ使用しないかもしれません!
プロセスがアクティブに書き込みを行っているためデータベースがロックされているかどうかを確認するための最良かつ唯一の方法(したがって、操作が完了するまで地獄に放置する必要があります)はmd5(または一部のシステムではmd5sum)ですファイルを2回。 別のチェックサムを取得した場合、データベースは書き込まれますが、破損したテーブル/データベースを簡単に作成できるため、本当にそのプロセスを強制終了したくありません。
繰り返しますが、それは重要です-解決策はロックプログラムを見つけてそれを殺すことではありません-正当な理由でデータベースに書き込みロックがあるかどうかを見つけて、そこから行くことです。時々、正しい解決策は単なるコーヒーブレイクです。
このロックされているが書き込まれていない状況を作成する唯一の方法は、プログラムが BEGIN EXCLUSIVE
を実行する場合です。 reasonはその後 END
を送信せず、プロセスは終了しません。適切に記述されたコードでは、3つの条件がすべて満たされる可能性は非常に低く、そのため、ロックプロセスを強制終了したい場合に100回のうち99回、ロックプロセスは正当な理由で実際にデータベースをロックしています。プログラマーは通常、同時実行を防ぎ、ユーザーの苦情を増やすため、本当に必要な場合を除き、 BEGIN EXCLUSIVE
条件を追加しません。 SQLite自体は、本当に必要なときにのみ追加します(インデックス作成時など)。
最後に、いくつかの答えが述べているように、「ロック済み」ステータスはファイル内に存在しません。これはオペレーティングシステムのカーネルに存在します。 BEGIN EXCLUSIVE
を実行したプロセスが、ファイルのロックをOSに要求しました。排他プロセスがクラッシュした場合でも、OSはファイルロックを維持する必要があるかどうかを判断できます!!ロックされたデータベースで終わることはできませんが、どのプロセスもそれをアクティブにロックしていません!!
どのプロセスがファイルをロックしているかを確認する場合は、通常、fuserよりもlsofを使用する方が適切です(これは、理由の良いデモンストレーションです: https://unix.stackexchange.com/questions/94316/fuser-vs-lsof-to-check-files-in-use ) 。または、DTrace(OSX)がある場合は、ファイルでiosnoopを使用できます。
似たようなことが起こった-私のWebアプリケーションはデータベースから読み取ることができたが、挿入または更新を実行できなかった。 Apacheを再起動すると、少なくとも一時的に問題が解決しました。
ただし、根本的な原因を突き止めることができると便利です。
lsof コマンドを実行すると、ファイルを開いたままプロセスがハングしていることがわかりました。
プロセスを終了し、問題を解決しました。
このリンクは問題を解決します。 : Sqliteが提供する場合:データベースロックエラー それは私の問題を解決しました。あなたに役立つかもしれません。
また、トランザクションの開始とトランザクションの終了を使用して、将来データベースをロックしないようにすることができます。
データベースの内部問題であるはずです...
私にとっては、" SQLite manager"でデータベースを閲覧しようとすると明らかになりました...
そのため、データベースに接続する別のプロセスが見つからず、修正できない場合は、
この根本的な解決策を試してください:
- テーブルのエクスポートを提供します(Firefoxでは" SQLite manager"を使用できます)
- 移行によってデータベーススキームが変更された場合、最後に失敗した移行を削除します
- " database.sqlite"の名前を変更しますファイル
- " rake db:migrate"を実行します新しい作業データベースを作成する
- テーブルのインポートのためにデータベースに適切な権限を付与する
- バックアップしたテーブルをインポートします
- 新しい移行を作成する
- "
rake db:migrate
" で実行します
端末セッションからPythonスクリプトを実行しているMac OS X 10.5.7で、この同じ問題に遭遇しました。スクリプトを停止し、ターミナルウィンドウがコマンドプロンプトに表示されていたとしても、次回の実行時にこのエラーが発生しました。解決策は、ターミナルウィンドウを閉じてから再度開くことでした。私には意味がありませんが、うまくいきました。
同じエラーが発生しました。 google-ingを5分行った後、dbを使用していた1つのシェルウィッチを閉じていないことがわかりました。 閉じてもう一度やり直してください;)
同じ問題がありました。どうやら、ロールバック機能は、dbファイルと同じであるが最新の変更がないジャーナルでdbファイルを上書きするようです。これを以下のコードに実装し、それ以降は正常に機能していますが、データベースがロックされたままであるため、コードがループにとどまる前です。
これが役立つことを願って
私の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つは、読み取り操作用のリソースを保持したまま書き込み操作を行おうとしている場合です。たとえば、テーブルからSELECTして、最初にResultSetを閉じずに選択したものを更新しようとした場合。
再起動オプションを下げる前に、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
データベースを使用して、pid 3556(manage.py)の別のPythonプログラムがあることを示しました。
上記の回答を読んで最近行った手順は、多くの回答がある古い質問ですが、私の場合、問題はcifsリソースの共有が原因でした。このケースは以前に報告されていないため、誰かの助けになることを願っています。
- Javaコードで接続が開いたままになっていないことを確認します。
- lsofでSQLite dbファイルを使用している他のプロセスがないことを確認します。
- 実行中のjvmプロセスのユーザー所有者にファイルに対するr / wパーミッションがあることを確認します。
-
接続の開口部で強制的にロックモードを試してください
final SQLiteConfig config = new SQLiteConfig(); config.setReadOnly(false); config.setLockingMode(LockingMode.NORMAL); connection = DriverManager.getConnection(url, config.toProperties());
NFS共有フォルダーでSQLite dbファイルを使用する場合は、このポイント 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データベースは、3台のサーバーで共有されるNFSファイルシステム上にあります。 2台のサーバーで、データベースに対してクエリを正常に実行できましたが、3台目のサーバーでは、「データベースがロックされています」と表示されていました。メッセージ。
この3番目のマシンの問題は、 / var
にスペースが残っていないことでした。このファイルシステムにあるSQLiteデータベースでクエリを実行しようとするたびに、「データベースがロックされています」というメッセージが表示されます。メッセージとログ上のこのエラー:
8月8日10:33:38 server01カーネル:lockd:172.22.84.87を監視できません
そしてこれも:
8月8日10:33:38 server01 rpc.statd [7430]:挿入に失敗しました:書き込み/var/lib/nfs/statd/sm/other.server.name.com:デバイスにスペースが残っていません 8月8日10:33:38 server01 rpc.statd [7430]:172.22.84.87のSM_MONのserver01へのSTAT_FAIL
スペースの状況が処理された後、すべてが正常に戻りました。
以前のコメントから、-journalファイルが存在すると述べました。
これは、トランザクションを開いて(排他的?)、まだデータをコミットしていないことを意味します。プログラムやその他のプロセスで-journalを残しましたか?
sqliteプロセスを再起動すると、ジャーナルファイルが確認され、コミットされていないアクションがクリーンアップされ、-journalファイルが削除されます。
Seun Osewa 氏が述べたように、たとえそれが可能であるとは思わなかったとしても、ゾンビ プロセスがロックを取得した状態でターミナル内に留まることがあります。スクリプトが実行されてクラッシュし、プロンプトに戻ると、ライブラリ呼び出しによってどこかにゾンビ プロセスが生成され、そのプロセスがロックされています。
(OSX 上で) 使用していたターミナルを閉じるとうまくいく場合があります。再起動すると機能します。(たとえば) 何も行っていない「Python」プロセスを探して、それらを強制終了することができます。
これを試すことができます: .timeout 100
でタイムアウトを設定します。
私はコマンドラインで何が起こるかわかりませんが、これを行うとC#.Netで:" UPDATE table-name SET column-name = value;"
Database is locked but this < code>&quot; UPDATE table-name SET column-name = value&quot; それはうまくいく。
;を追加すると、sqliteはさらにコマンドを探します。
LiteDACコンポーネントでDelphiを使用すると、このエラーが発生しました。 ConnectedプロパティがSQLite接続コンポーネント(この場合はTLiteConnection)に対してTrueに設定されている場合にのみ、Delphi IDEからアプリを実行しているときに発生しました。
「データベースがロックされています」と言っていました SQLITE_BUSY の結果コードであると思われる、マルチスレッドアプリケーションのエラー sqlite3_busy_timeout を30000のような適切な長さに設定することで解決しました。
(補足説明として、7年前の質問で誰もこれを見つけていないのは奇妙なことです!SQLiteは本当に奇妙で素晴らしいプロジェクトです...)