38

現在、SQLite3 を使用して Rails サイトを運営しています。

500 リクエストごとに約 1 回、

ActiveRecord::StatementInvalid (SQLite3::BusyException: データベースがロックされています:...

私のコードへの侵襲を最小限に抑えるこれを修正する方法は何ですか?

DBをソース管理に保存できるため、バックアップが自然になり、変更を非常に迅速にプッシュできるため、現在SQLLiteを使用しています。ただし、同時アクセス用に設定されていないことは明らかです。明日の朝、MySQL に移行します。

4

16 に答える 16

57

You mentioned that this is a Rails site. Rails allows you to set the SQLite retry timeout in your database.yml config file:

production:
  adapter: sqlite3
  database: db/mysite_prod.sqlite3
  timeout: 10000

The timeout value is specified in miliseconds. Increasing it to 10 or 15 seconds should decrease the number of BusyExceptions you see in your log.

This is just a temporary solution, though. If your site needs true concurrency then you will have to migrate to another db engine.

于 2009-04-10T22:15:41.217 に答える
9

デフォルトでは、データベースがビジーでロックされている場合、sqlite はブロックされたビジー エラーですぐに戻ります。あきらめる前に、しばらく待ってから試してみるように頼むことができます。sqliteが不適切であることに同意する場合、データベースにアクセスする数千のスレッドがない限り、これは通常問題を解決します。

    // データベースがロックされている場合、SQLite を待機して最大 100 ミリ秒再試行するように設定します
    sqlite3_busy_timeout(デシベル、100);
于 2008-09-18T18:21:29.607 に答える
3

これらはすべて真実ですが、次のような質問には答えていません。なぜ私の Rails アプリは本番環境で SQLite3::BusyException を発生させることがあるのでしょうか?

@Shalmanese: 本番ホスティング環境はどのようなものですか? 共有ホスト上にありますか? NFS 共有上の sqlite データベースを含むディレクトリですか? (おそらく、共有ホスト上)。

この問題は、NFS 共有によるファイル ロックの現象と、SQLite の同時実行性の欠如に関係している可能性があります。

于 2010-11-19T15:40:49.503 に答える
2
bundle exec rake db:reset

それは私にとってはうまくいき、保留中の移行がリセットされて表示されます。

于 2015-02-13T07:09:43.450 に答える
2

記録のために。Rails 2.3.8 のあるアプリケーションで、Rifkin Habsburg が提案した「タイムアウト」オプションを Rails が無視していることがわかりました。

さらに調査した結果、Rails dev に関連する可能性のあるバグが見つかりました: http://dev.rubyonrails.org/ticket/8811。さらに調査した結果、解決策が見つかりました(Rails 2.3.8 でテスト済み)。

この ActiveRecord ファイルを編集します: activerecord-2.3.8/lib/active_record/connection_adapters/sqlite_adapter.rb

これを置き換えます:

  def begin_db_transaction #:nodoc:
    catch_schema_changes { @connection.transaction }
  end

  def begin_db_transaction #:nodoc:
    catch_schema_changes { @connection.transaction(:immediate) }
  end

そしてそれだけです!パフォーマンスの低下は見られず、アプリは中断することなく、より多くの請願をサポートするようになりました (タイムアウトを待機します)。スクライトいいですね!

于 2011-05-23T15:46:39.990 に答える
1

Sqlite は、現在のプロセスが終了するまで他のプロセスを待機させることができます。

複数のプロセスが Sqlite DB にアクセスしようとしている可能性があることがわかっている場合は、次の行を使用して接続します。

conn = sqlite3.connect('ファイル名', isolation_level = 'exclusive' )

Python Sqlite ドキュメントによると:

connect() 呼び出しの isolation_level パラメータ、または接続の isolation_level プロパティを介して、pysqlite が暗黙的に実行する (またはまったく実行しない) BEGIN ステートメントの種類を制御できます。

于 2009-04-11T03:45:18.117 に答える
0

sqlite3 ruby​​ 拡張機能でデッドロックを見つけたので、ここで修正します。試してみて、これで問題が解決するかどうかを確認してください。

    https://github.com/dxj19831029/sqlite3-ruby

プルリクエストを開きましたが、彼らからの応答はもうありません。

とにかく、sqlite3 自体で説明されているように、何らかのビジー例外が予想されます。

この状態に注意してください: sqlite ビジー

    ビジー ハンドラーが存在しても、それが呼び出されることは保証されません。
    ロック競合。SQLite がビジー ハンドラーを呼び出すとエラーが発生する可能性があると判断した場合
    デッドロックの代わりに SQLITE_BUSY または SQLITE_IOERR_BLOCKED を返します。
    ビジー ハンドラーを呼び出します。1 つのプロセスが読み取りロックを保持しているシナリオを考えてみましょう
    予約済みロックに昇格しようとしていて、2 番目のプロセスが予約済みロックを保持していること
    排他ロックに昇格しようとしているロック。最初のプロセスを続行できません
    2 番目のプロセスによってブロックされ、2 番目のプロセスが続行できないためです。
    最初にブロックされました。両方のプロセスがビジー ハンドラを呼び出した場合、どちらも何もしません。
    進捗。したがって、SQLite は最初のプロセスに対して SQLITE_BUSY を返します。
    最初のプロセスに読み取りロックを解放させ、2 番目のプロセスが
    続行。

この条件を満たした場合、タイムアウトは無効になります。それを避けるために、begin/commit 内に select を置かないでください。または、begin/commit に排他ロックを使用します。

お役に立てれば。:)

于 2012-11-02T04:55:16.707 に答える
0

ああ、先週の私の存在の悩みの種。プロセスがデータベースに書き込むと、 Sqlite3 は db ファイルをロックします。IE 任意の UPDATE/INSERT タイプのクエリ (何らかの理由で count(*) も選択します)。ただし、複数の読み取りを問題なく処理します。

それで、私は最終的に、データベース呼び出しの周りに独自のスレッドロックコードを書くのに十分なほどイライラしました. アプリケーションがデータベースに書き込むスレッドを常に 1 つだけにすることで、数千のスレッドにスケーリングすることができました。

そして、ええ、それは地獄のように遅いです。しかし、それは十分に高速で正しいものでもあります。これは、持っていると便利なプロパティです。

于 2008-09-17T01:33:32.783 に答える
0

これは、多くの場合、同じデータベースにアクセスする複数のプロセスの連続した障害です。つまり、RubyMine で「1 つのインスタンスのみを許可する」フラグが設定されていない場合です。

于 2013-01-31T12:38:00.070 に答える
0

出典:このリンク

- Open the database
db = sqlite3.open("filename")

-- Ten attempts are made to proceed, if the database is locked
function my_busy_handler(attempts_made)
  if attempts_made < 10 then
    return true
  else
    return false
  end
end

-- Set the new busy handler
db:set_busy_handler(my_busy_handler)

-- Use the database
db:exec(...)
于 2008-09-17T01:14:50.380 に答える
0

ロックが発生したときにアクセスされているテーブルは?

長時間の取引はありますか?

ロックが発生したときにまだ処理されていたリクエストを特定できますか?

于 2008-09-17T01:17:57.877 に答える
-9

これは、トランザクションがタイムアウトしたときに発生すると思います。「実際の」データベースを使用する必要があります。Drizzle や MySQL のようなものです。上記の 2 つのオプションよりも SQLite を好む理由はありますか?

于 2008-09-17T01:05:23.350 に答える