仕事用に書いたこのプログラムを改善しようとしています。最初は急いでいましたが、彼らはパフォーマンスなど気にしませんでした。そこで、データベース全体 (SQLite データベース) に対してクエリを実行し、関数で使用するために結果をリストに格納するという恐ろしい決定を下しました。しかし、私は現在、各関数をスレッド化して、必要なデータベースの部分のみを関数に照会させることを検討しています。〜25の機能があります。私の質問は、これは安全ですか?また、その数の同時接続を持つことは可能ですか? データベースから情報をプルするだけで、挿入や更新はしません。
3 に答える
私が説明した方法[*]は、各同時スレッドがデータベースへの独自の接続を開くようにすることです。各接続は一度に1つのクエリまたは変更しか処理できないためです。接続されたスレッドのグループは、同時読み取りを簡単に実行できます。多数の同時書き込みで重大な問題が発生し、過度のブロッキングやロックの取得の失敗が発生した場合は、SQLiteの機能を超えていることになります(PostgreSQLのようなサーバーベースのDBを検討する必要があります)。 。
便利な場合は、マスタースレッドにワーカースレッドの接続を開かせることもできますが、実際には1つのスレッドからの各接続のみを使用することをお勧めします(正気のために!) 。
[*SQLiteの通常のビルドの場合。もちろん、ビルド時にオフにすることは可能です。]
25 の同時接続は賢明な考えではありません。それは膨大な数です。
私は通常、この問題に対して多層設計を作成します。内部キャッシュを持つ一種の ObjectFactory クラスを介して、すべてのリクエストをデータベースに送信します。ObjectFactory はリクエストを ConnectionPoolHandler に転送し、結果をそのキャッシュに保存します。この接続プール ハンドラは、X 個の同時接続を使用しますが、複数のスレッドにディスパッチします。
ただし、この設計を適用する前に、いくつかの注意事項を作成する必要があります。まず、次の 2 つの質問を自問する必要があります。
- あなたのアプリケーションは、このデータベースにアクセスできる唯一のアプリケーションですか?
- あなたのアプリケーションは、このデータベースのデータを変更する唯一のアプリケーションですか?
最初の質問が否定的である場合、ロックの問題が発生する可能性があります。2 番目の質問の答えが否定的である場合、キャッシュを適用することは非常に困難です。すべてのキャッシュを実装したくない場合もあります。
キャッシュは、主キーなどの一意の参照に基づいてオブジェクトを頻繁に要求する場合に特に役立ちます。その場合、最も頻繁に使用されるオブジェクトをマップに保存できます。キャッシングの一般的なコレクションは、「LRUMap」(「Least-Recently-Used」マップ) です。このコレクションの利点は、最も頻繁に使用されるオブジェクトが自動的に一番上に配置されることです。同時に、最大サイズがあり、めったに使用されないアイテムをマップから自動的に削除します。
キャッシュの 2 つ目の利点は、各オブジェクトが一度しか存在しないことです。例えば:
- Employee がデータベースからフェッチされます。
- ObjectFactory は、結果セットを実際のオブジェクト インスタンスに変換します。
- ObjectFactory はすぐにキャッシュに格納します。
- 少し後、SQL "... where name like "John%" ステートメントを使用して多数の従業員が取得されます。
- 結果セットをオブジェクトに変換する前に、ObjectFactory はまず、これらのレコードの ID がおそらく既にキャッシュに格納されているかどうかを確認します。
- マッチが見つかりました!あはは、このオブジェクトを再作成する必要はありません。
特定のオブジェクトをメモリ内に 1 回だけ保持することには、いくつかの利点があります。
最後になりましたが、Java には「弱い参照」のようなものがあります。これらは、ガベージ コレクターによって実際にクリーンアップできる参照である参照です。C# に存在するかどうか、およびどのように呼び出されるかはわかりません。これを実装することで、キャッシュされたオブジェクトの最大量を気にする必要さえなくなり、ガベージ コレクターが処理してくれます。
SQLite には書き込みの同時実行性はありませんが、同時に読み取る任意の数の接続をサポートしています。すべてのスレッドに独自の接続があることを確認してください。