9

どこに聞いたらいいのかよくわかりませんが、ここにあるといいのですが。

私が探しているのは、DBがビジーの場合にSQLiteクエリを再試行する最も簡単なソリューションです。サーバー上のIRCクライアントとしてquasselを使用していますが、古いログを別のDBに移動して、使用するログを小さくしたいと考えています。それを行うために私が書いたスクリプトは次のとおりです。

CREATE TEMP TABLE delfrom (id integer,val integer);
ATTACH '/home/irc/oldlog.db' as log;
BEGIN IMMEDIATE;
REPLACE INTO delfrom (id,val) select 1337,messageid from backlog where time < strftime('%s', 'now','-14 days') ORDER BY messageid DESC LIMIT 1;
INSERT INTO log.log (messageid,time,bufferid,type,flags,senderid,message) SELECT messageid,time,bufferid,type,flags,senderid,message FROM backlog WHERE messageid < (SELECT val FROM delfrom where id=1337);
DELETE FROM backlog WHERE messageid < (SELECT val FROM delfrom where id=1337);
PRAGMA incremental_vacuum;
COMMIT;

そして、sqlite3quassel-storage.sqlite<movelog.sqlを使用して実行します

問題は、これが実行されている間、quasselが実行BEGIN IMMEDIATE;されているため、DBがロックされているために失敗することがあるということです。

誰かが私にその設定を変更する簡単な方法を提案して、クエリが機能するまで数秒ごとに再試行されるようにすることはできますか?Python SQLiteラッパーにそれが組み込まれていることを読みましたか?これをアクティブにする特別な方法はありますか?さらに重要なのは、Pythonを使用して2番目のDBをアタッチできますか?にタイムアウトパラメータがありますが、sqlite3.connectそれがどのように機能するかはよくわかりません。Pythonは、接続ごとに書き込むためにDB全体をロックしますか?

私はPythonの使用に固執しているわけではありません。私が好む解決策は、このエラーが発生したときにsqlite3が0を返し、それをシェルのループにラップすることですが、それは機能しないようです。

4

3 に答える 3

14

テーブルがロックされている場合、Pythonは定期的に再試行します。データベースがロックされている場合、再試行は行われません。テーブルロックは、スレッド、共有接続、またはその他の方法によって、同じプロセス内でのみ伝播されます。

データベースロックは、複数のプロセスがファイルに書き込むときに発生し、(簡単に言えば)ジャーナルが存在する限り存在します。

これを回避するために、WALモードをジャーナルに使用できます。(プラグマjournal_mode = wal;)

データベースロックをスピンするには、execute関数を次のようにラップする必要があります。

for x in range(0, timeout):
  try:
    with connection:
      connection.execute(sql)
  except:
     time.sleep(1)
     pass
  finally:
     break
else:
    with connection:
        connection.execute(sql)  

最後の接続ブロックにより、例外が適切に返されます。これは、ロックされたデータベースの例外をチェックするか、元の例外を発生させることによって改善する必要がありますが、それは読者の演習として残されています。

于 2014-03-28T09:30:08.117 に答える
14

バージョンが3.7より大きい場合は、SqliteにWALモードを使用しますhttps://www.sqlite.org/wal.html

connect = sqlite3.connect(DB, **kwargs)
connect.execute("PRAGMA journal_mode=WAL")

ドキュメントによると、「リーダーはライターをブロックせず、ライターはリーダーをブロックしないため、WALはより多くの同時実行性を提供します。読み取りと書き込みは同時に続行できます。」

于 2016-09-01T07:22:08.610 に答える
8

タイムアウトを十分に高く設定している場合、SQLiteライブラリ自体は定期的に再試行します。

デフォルトのPythonラッパーでは、これはsqlite3.connectの2番目のパラメーターです。

于 2013-02-28T19:59:50.977 に答える