web-dev-qa-db-ja.com

SQLiteデータベースのロックを解除するにはどうすればいいですか?

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

これが機能するようにデータベースをロック解除するにはどうすればよいですか?

235
ryantm

Windowsでは、このプログラムを試すことができます http://www.nirsoft.net/utils/opened_files_view.html プロセスを調べるためにdbファイルを処理しています。データベースのロックを解除するためにそのプログラムを閉じてみてください

LinuxとmacOSでは、たとえばロックされたファイルがdevelopment.dbの場合、同様のことができます。

$ fuser development.db

このコマンドはどのプロセスがファイルをロックしているかを示します。

> development.db:5430

プロセスを強制終了するだけです...

殺す-9 5430

...そしてデータベースはロック解除されます。

235
noneno

書き込み中にアプリをクラッシュさせるとsqliteデータベースがロックされました。これは私がそれをどのように修正したかです:

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

撮影元: http://random.kakaopor.hu/how-to-repair-an-sqlite-database

86
robert

SQLiteのwiki DatabaseIsLocked のページにこのエラーメッセージの詳しい説明があります。それは、部分的には、競合の原因は(エラーを出しているプロセスにとって)内部的なものであると述べています。

このページで説明されていないのは、SQLiteがプロセス内の何かがロックを保持しているとどのように判断し、どのような条件が誤検出につながる可能性があるかを判断することです。

51
converter42

-journalファイルを削除するのはひどい考えのようです。 sqliteがクラッシュ後にデータベースを一貫した状態にロールバックできるようにするためのものです。データベースが矛盾した状態にあるときに削除すると、破損したデータベースが残ります。 sqliteサイトからページを引用する

クラッシュや停電が発生してホットジャーナルがディスクに残っている場合は、データベースファイルが別のSQLiteプロセスによって開かれてロールバックされるまで、元のデータベースファイルとホットジャーナルが元の名前でディスクに残ることが重要です。 。 [...]

SQLiteリカバリの一般的な障害モードは次のようになっていると思われます。電源障害が発生した。電源が回復した後、善意あるユーザーまたはシステム管理者がディスクの損傷を探し始めます。彼らは彼らのデータベースファイル "important.data"を見ます。このファイルはおそらく彼らにはおなじみのものです。しかしクラッシュ後、 "important.data-journal"というホットジャーナルもあります。その後、ユーザーはホットジャーナルを削除し、システムのクリーンアップを支援していると考えます。ユーザー教育以外にこれを防ぐ方法はありません。

ロールバックは、次回データベースが開かれたときに自動的に行われると想定されていますが、プロセスがデータベースをロックできない場合は失敗します。他の人が言っているように、これに対する1つの考えられる理由は別のプロセスが現在それを開いているということです。データベースがNFSボリューム上にある場合、もう1つの可能性は古いNFSロックです。その場合の回避策は、データベースファイルをNFSサーバーでロックされていない新しいコピー(mv database.db original.db; cp original.db database.db)に置き換えることです。 sqlite FAQは、NFSファイルロックの実装にバグがあるため、NFSボリューム上のデータベースへの同時アクセスに関する注意を推奨しています。

-journalファイルを削除すると、以前はできなかったデータベースがロックされるのはなぜでしょうか。それは再現可能ですか?

ちなみに、-journalファイルが存在していても、必ずしもクラッシュが発生したことやロールバックされる変更があることを意味するわけではありません。 Sqliteにはいくつかのジャーナルモードがあり、PERSISTまたはTRUNCATEモードでは、常に-journalファイルをそのままにしたまま、内容を変更してロールバックする部分的なトランザクションがあるかどうかを示します。

30
Aaron

プロセスがSQLite DBをロックしてクラッシュした場合、DBは永久にロックされたままになります。それが問題です。他のプロセスがロックしているわけではありません。

13
Phil

「データベースがロックされています」というエラーを削除したい場合は、次の手順に従ってください。

  1. データベースファイルを他の場所にコピーします。
  2. データベースをコピーしたデータベースと置き換えます。これはあなたのデータベースファイルにアクセスしていたすべてのプロセスを間接参照します。
13
vinayak jadi

sQLiteのdbファイルは単なるファイルなので、最初のステップはそれが読み取り専用ではないことを確認することです。他にやるべきことは、DBを開いた状態である種のGUI SQLite DBビューアがないことを確認することです。 DBを別のシェルで開くことも、コードでDBを開くこともできます。通常、これは、別のスレッド、またはSQLiteデータベースブラウザなどのアプリケーションでDBが書き込み用に開かれている場合に発生します。

10
Heat Miser

私は今、NFSマウントに保存されたリモートサーバー上のSQLiteデータベースを使用して、この問題を抱えていました。データベースが開いている間に使用したリモートシェルセッションがクラッシュした後、SQLiteはロックを取得できませんでした。

上で提案した回復のレシピは私にはうまくいきませんでした(最初にデータベースを移動してからコピーするという考えも含めて)しかし、それを非NFSシステムにコピーした後、データベースは使用可能になり、データは失われていないように見えます。

9
jogojapan

私のロックはシステムがクラッシュしたことによるもので、ハングしたプロセスによるものではありません。これを解決するために、私は単にファイルの名前を変更し、それを元の名前と場所にコピーして戻しました。

それはLinuxのシェルを使用することです...

mv mydata.db temp.db
cp temp.db mydata.db
5
Ben L

SQLiteでのさまざまなロック状態の ドキュメント が非常に役立つことがわかりました。 Michael、あなたが読み取りを実行することはできてもデータベースへの書き込みを実行することができない場合、それはプロセスがあなたのデータベースに対してRESERVEDロックを取得したがまだ書き込みを実行していないことを意味します。 SQLite3を使用している場合は、PENDINGと呼ばれる新しいロックがあります。これ以上のプロセスは接続できませんが、既存の接続は読み取りを実行することができます。そのため、これを検討してください。

4
Kyle Cronin

接続文字列に "Pooling=true"を追加して動作しました。

4
user1900210

このエラーは、ファイルが共有フォルダなどのリモートフォルダにある場合にスローされる可能性があります。私はデータベースをローカルディレクトリに変更しましたが、それは完璧に機能しました。

4
Zequez

私は2つの接続からSQLiteにアクセスするアプリ内でそのような問題を抱えています - 1つは読み取り専用で、もう1つは書き込みと読み取り用でした。読み取り専用接続が2番目の接続からの書き込みをブロックしているようです。最後に、使用後すぐに準備文を確定またはリセットする必要があることがわかりました。準備された文が開かれるまでは、データベースへの書き込みがブロックされていました。

忘れてはいけない呼び出し:

sqlite_reset(xxx);

または

sqlite_finalize(xxx);
3
Mike Keskinov

INDEXのようないくつかの関数は非常に長い時間がかかることがあります - そしてそれは実行中にデータベース全体をロックします。そのような場合、ジャーナルファイルさえも使用しないかもしれません。

そのため、プロセスが実際にデータベースに書き込んでいるためにデータベースがロックされているかどうかをチェックする最良の方法は、ファイルを2回md5(または一部のシステムではmd5sum)することです。 。別のチェックサムを取得した場合、データベースは書き込まれていますが、破損したテーブルやデータベースが作成された場合は簡単に破損する可能性があるため、本当にそのプロセスを強制終了したくはありません。

繰り返しますが、これは重要なので、解決策はロックプログラムを見つけて強制終了するのではなく、正当な理由でデータベースに書き込みロックがあるかどうかを確認して、そこから進むことです。時々正しい解決策はただコーヒーブレークです。

この書き込み禁止の状況を作成する唯一の方法は、プログラムがBEGIN EXCLUSIVEを実行した場合です。これは何らかのテーブルの変更などを実行したいため、何らかの理由で後でENDを送信することはありませんプロセスは終了しません。 3つの条件がすべて満たされていることは、適切に書かれたコードにはほとんどあり得ません。そのため、誰かが自分のロックプロセスを殺したい場合、100のうち99倍になります。プログラマーは通常、必要がない限りBEGIN EXCLUSIVE条件を追加しません。並行性が妨げられ、ユーザーの苦情が増えるためです。 SQLite自身は本当に必要なときだけそれを追加します(インデックス作成のときのように)。

最後に、 'ロックされた'ステータスはいくつかの答えが述べているようにファイル内には存在しません - それはオペレーティングシステムのカーネルに存在します。 BEGIN EXCLUSIVEを実行したプロセスは、ファイルにロックをかけるようにOSから要求しました。あなたの排他的なプロセスがクラッシュしたとしても、あなたのOSはそれがファイルロックを維持するべきであるかどうか把握することができるでしょう!データベースがロックされてしまうことはあり得ませんが、アクティブにロックしているプロセスはありません。どのプロセスがファイルをロックしているかを知るには、fuserよりもlsofを使用するのが一般的です(これはその理由の良い例です。 https://unix.stackexchange.com/questions/94316/fuser-)。 vs-lsof-to-use-files-in-use )。あるいはDTrace(OSX)がある場合は、ファイルにiosnoopを使用できます。

3
J.J

このリンクは問題を解決します。 : Sqliteの場合:データベースロックエラー 解決した私の問題は役に立つかもしれません。

また、トランザクションの開始と終了のトランザクションを使用して、将来データベースをロックしないようにすることもできます。

2
shreeji

データベースの内部問題になるはずです...
私にとって、それは "SQLite manager"でデータベースを閲覧しようとした後に現れました...
それで、あなたが他のプロセスがデータベースに接続するのを見つけることができず、あなたがそれを直すことができないのであれば、ただこの根本的な解決策を試してみてください。

  1. あなたのテーブルをエクスポートするために提供します(あなたはFirefox上で "SQLite manager"を使うことができます)
  2. 移行によってデータベーススキーマが変更された場合は、最後に失敗した移行を削除します。
  3. "database.sqlite"ファイルの名前を変更する
  4. "rake db:migrate"を実行して新しい作業データベースを作成します。
  5. テーブルのインポートのためにデータベースに適切な権限を与えるために提供します
  6. バックアップしたテーブルをインポートする
  7. 新しいマイグレーションを書く
  8. "rake db:migrate"で実行してください
2
Davide Ganz

私のWebアプリケーションはデータベースから読み取ることができましたが、挿入や更新を実行できませんでした。 Apacheを再起動することで、少なくとも一時的に問題が解決しました。

しかし、根本的な原因を突き止めることができるのはいいことです。

2
Michael Cox

lsof私のLinux環境でコマンドを実行すると、ファイルを開いたままにしているプロセスがハングしていることがわかりました。
プロセスを終了し、問題は解決しました。

2
PinkSheep

この例外が発生する一般的な理由の1つは、読み取り操作用のリソースを保持したまま書き込み操作を実行しようとしているときです。たとえば、テーブルからSELECTを実行し、次にResultSetを閉じずに、選択したものをUPDATEしようとしたとします。

1
Martin Carney

ここで説明したものとは少し異なるシナリオでこのエラーが発生しました。

SQLiteデータベースは、3台のサーバーで共有されているNFSファイルシステムに置かれていました。 2台のサーバーで、データベースに対して正常にクエリを実行できました。3台目のサーバーでは、「データベースはロックされています」というメッセージが表示されていました。

この3台目のマシンの問題は/varにスペースが残っていなかったことです。このファイルシステムにあるSQLiteデータベースでクエリを実行しようとするたびに、 "データベースはロックされています"というメッセージが表示され、ログ全体にこのエラーが表示されます。

8月8日10時33分38秒server01カーネル:ロック: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]:SM_MONが172.22.84.87の場合、server01へのSTAT_FAIL

宇宙の状況が処理された後、すべては正常に戻りました。

1
ederribeiro

再起動オプションを選択する前に、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プログラムを持っていることを示しました。

1
Philip Clarke

私は、ターミナルセッションからPythonスクリプトを実行しているMac OS X 10.5.7で同じ問題に遭遇しました。スクリプトを停止してターミナルウィンドウが[プロンプト]コマンドの前に表示されていても、次回実行したときにこのエラーが発生します。解決策は端末ウィンドウを閉じてから再び開くことでした。意味がありませんが、うまくいきました。

1
Shawn Swaner

私は同じ問題を抱えていました。どうやらロールバック機能は、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
Jared

たくさんの答えがある古い質問ですが、上記の答えを読んで最近行った手順ですが、私の場合は、問題はcifsリソースの共有が原因でした。この症例は以前に報告されていないので、誰かに役立つことを願っています。

  • Javaコードで接続が開いたままになっていないことを確認してください。
  • 他のプロセスがあなたのSQLite dbファイルをlsofで使用していないことを確認してください。
  • 実行中の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 faqの this point を確認し、マウント構成オプションを確認して、回避ロックを確認します。 here

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

私はちょうど同じエラーがありました。 5分間のgoogle-ingの後、シェルを使っていた1人の魔女がデータベースを使用していないことがわかりました。閉じてもう一度やり直してください。

1
Flow

データを書き込もうとしていたときに作成したC#.NET 4.6.1アプリでもsqliteロックを受け取っていましたが、自分の開発マシン上のVisual Studioでアプリを実行していたときはそうではありませんでした。代わりに、アプリがリモートのWindows 10マシンにインストールされて実行されているときにのみ発生していました。

当初はファイルシステムのアクセス権だと思っていましたが、Nugetを使ってプロジェクトにインストールしたSystem.Data.SQLiteパッケージドライバ(v1.0.109.2)が問題の原因であることがわかりました。 NuGetパッケージを削除し、プロジェクト内の古いバージョンのドライバを手動で参照したところ、リモートマシンにアプリが再インストールされると、ロックの問題は魔法のように消えました。最新のドライバやNugetパッケージにバグがあるとしか思えません。

0
Mr Rowe

LiteDACコンポーネントと一緒にDelphiを使用すると、このエラーが発生しました。 SQLite接続コンポーネントに対してConnectedプロパティがTrueに設定されている場合(この場合はTLiteConnection)、Delphi IDEからアプリケーションを実行している間にのみ発生しました。

0
TheSteven

何らかの理由でデータベースがロックされました。これを修正する方法は次のとおりです。

  1. Sqliteファイルを私のシステムにダウンロードしました(FTP)
  2. オンラインのsqliteファイルを削除しました
  3. ファイルをホスティングプロバイダにアップロードし直しました

今はうまくいきます。

0
Mohsin

私の場合は、このエラーも発生しました。

データベースのロックの原因となっている可能性のある他のプロセス(SQLite Manager、私のデータベースに接続する他のプログラム)については、既に確認しました。しかし、それに接続するプログラムは他にはありません。同じアプリケーション内でアクティブなSQLConnectionだけで、connected

new SQLConnectionを確立する前に、まだ接続されている可能性がある前にactive SQLConnectionを調べてみてください。新しいコマンド

0
Wennie

これは、他のクエリがそのデータベースで実行されているためです。 SQLiteはクエリが同期的に実行されるデータベースです。したがって、他の誰かがそのデータベースを使用している場合は、クエリまたはトランザクションを実行すると、このエラーが発生します。

そのため、特定のデータベースを使用しているプロセスを停止してからクエリを実行します。

0

ChromeデータベースSQLiteで表示 のロックを解除しようとしている場合は、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

マック

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

これを試すことができます:.timeout 100タイムアウトを設定します。私はコマンドラインで何が起こるかわかりませんが、これを行うとC#.Netで:"UPDATE table-name SET column-name = value;"データベースがロックされますが、これは"UPDATE table-name SET column-name = value"うまくいきます。

;を追加すると、sqliteはさらにコマンドを探します。

0
nXqd

あなたの以前のコメントから、あなたは-journalファイルが存在すると言いました。

これは、あなたがトランザクションをオープンし(排他的に?)、まだデータをコミットしていないことを意味します。あなたのプログラムや他のプロセスが-journalを残しましたか?

Sqliteプロセスを再起動すると、ジャーナルファイルが調べられ、コミットされていないアクションがあればそれをクリーンアップし、-journalファイルを削除します。

0
daivd cameron

Seun Osewaが言ったように、たとえあなたがそれが可能であると思わないとしても時々ゾンビプロセスは獲得されたロックで端末に座るでしょう。スクリプトが実行されてクラッシュし、プロンプトに戻りますが、ライブラリ呼び出しによってどこかにゾンビプロセスが生成され、そのプロセスがロックされています。

あなたが(OSX上で)いた端末を閉じることはうまくいくかもしれません。再起動はうまくいきます。何もしていない(たとえば) "python"プロセスを探してそれらを殺すことができます。

0
wisty

マルチスレッドアプリケーションでも "database is locked"エラーが発生していました。これは SQLITE_BUSY 結果コードのようです。 sqlite3_busy_timeout を何かに設定することで解決しました。適切には30000のように長いです。

(ちなみに、7年前の質問でこれをまだ誰も見つけていないのは、おかしなことですが!SQLiteは本当に独特で素晴らしいプロジェクトです...)

0
Stijn Sanders