14

SQLiteデータベースを処理する2つ以上のプロセス(「プレーヤー」プロセスと多くの「エディター」プロセス)があるとしましょう。

「プレーヤー」プロセスはデータベースを読み取り、ビューを更新します。私の場合、データベースに保存されているイベントに応じて、波形がサウンドカードにミックスされます。

「エディター」プロセスは、そのデータベースのエディターです。データベースを絶えず変更します。

ここで、プレーヤーに編集の変更をすばやく反映させたいと思います。

SQLiteが同じプロセス内のデータベースの変更を追跡するためのフックを提供していることは知っていますが、複数のプロセスでこれを行う方法についてはほとんど情報がないようです。

データベースを絶えずポーリングし、レコードを比較し、イベントをトリガーすることはできますが、特にデータベースが大きくなると、それは非常に非効率的なようです。

ログテーブルとトリガーの使用を考えていますが、もっと簡単な方法があるのではないかと思います。

4

8 に答える 8

4

リレーショナル データベースは、このための最適な最初の選択肢ではありません。

なんで?

すべての編集者がプレーヤーに変更を渡すようにします。

あなたのプレーヤーは、事実上、これらすべての編集者のためのサーバーです。プレーヤーには複数の開いている接続が必要です。変更については、これらすべての接続をリッスンする必要があります。それらの変更を表示する必要があります。

変更が非常に大きい場合は、編集者が変更保持してプレーヤーに通知するハイブリッド ソリューションに移行できます。

いずれにせよ、編集者はプレイヤーに変更があることを通知する必要があります。プレーヤーがデータベース内の変更を検出しようとするよりも、はるかに簡単です。


より良い設計は、エディターからのメッセージを受け取り、それらを保持し、プレイヤーに通知するサーバーです。このサーバーはエディターでもプレーヤーでもなく、すべてのメッセージが処理されることを保証するブローカーにすぎません。編集者やプレイヤーからの接続を受け入れます。データベースを管理します。

2 つの実装があります。サーバーはプレーヤーです。サーバーはプレーヤーとは別です。サーバーの設計は変更されません。プロトコルのみが変更されます。サーバーがプレーヤーの場合、サーバーはプレーヤー オブジェクトを直接呼び出します。サーバーがプレーヤーから分離されている場合、サーバーはプレーヤーのソケットに書き込みます。

プレーヤーがサーバーの一部である場合、エディターからメッセージを受信すると、プレーヤー オブジェクトが直接呼び出されます。プレーヤーが分離されている場合、小さなリーダーがソケットからメッセージを収集し、プレーヤー オブジェクトを呼び出します。

プレーヤーはサーバーに接続し、情報のストリームを待ちます。これは、エディターからの入力か、サーバーがデータベースに永続化したデータへの参照のいずれかです。

メッセージ トラフィックが十分に小さく、ネットワークの遅延が問題にならない場合、エディターはすべてのデータをサーバー/プレーヤーに送信します。メッセージ トラフィックが大きすぎる場合、エディターはデータベースに書き込み、データベースの FK のみを含むメッセージをサーバー/プレーヤーに送信します。


質問で「通知中にエディターがクラッシュした場合、プレーヤーは完全に台無しになります」を明確にしてください。

これは、プレーヤー サービスの設計としては不適切なように思えます。さまざまなエディターから状態を取得しない限り、「永久に台無し」になることはありません。エディターから状態を取得している場合 (ただし、その状態をミラーしようとしている場合など) は、プレイヤーが単にエディターから状態を取得し、「永久にめちゃくちゃ」にならないような設計を検討する必要があります。

于 2009-03-24T11:55:22.550 に答える
3

SQLiteには、update_hookあなたが望むことをする機能があります。

SQLite C インターフェイス

データ変更通知コールバック

void *sqlite3_update_hook(
    sqlite3*,
    void(*)(void *,int ,char const *,char const *,sqlite3_int64),
    void*
);

このsqlite3_update_hook()インタフェースは、最初の引数によって識別されるデータベース接続にコールバック関数を登録し、ROWID テーブルで行が更新、挿入、または削除されるたびに呼び出されます。同じデータベース接続に対するこの関数への以前の呼び出しによって設定されたコールバックはオーバーライドされます。

残念ながら、Python sqlite モジュールでは公開されていません...

これを利用するために(Pythonコードから)C APIを掘り下げる少しハックな回避策があります: https://stackoverflow.com/a/16920926

于 2014-03-13T21:03:29.777 に答える
2

2つのプロセス間のソケットを開き、エディターにすべてのプレーヤーに更新について通知してもらいます。

于 2009-03-24T11:40:26.547 に答える
2

その場合、データベースの読み取り/書き込みを管理するプロセスを作成すると思います。

データベースに何らかの変更を加える必要がある各編集者は、IPC やネットワークなどの方法で、このプロセスを呼び出します。

このプロセスは、データベースの変更をプレーヤーに通知できます。プレーヤーは、データを取得したい場合、データベースを管理しているプロセスに必要なデータを要求する必要があります。(または、db プロセスは、変更を通知するときに必要なものを通知するため、プレーヤーからの要求は必要ありません)

これを行うと、SQLite DB にアクセスするプロセスが 1 つだけになるという利点があるため、データベースでロックや同時実行の問題が発生しません。

于 2009-03-24T12:45:44.410 に答える
1

編集:同じマシン上のプロセスを想定しています。

私の意見では、次の 2 つの方法があります。

  • ポーリング(あなたが述べたように)、しかしそれを単一の値に保ちます(他のテーブルの LastUpdateTime を保持するだけのテーブルのように)

  • ターゲット プラットフォームで使用可能なプロセス間通信を使用します。これは、Windows のイベント (たとえば、C# では (Python ではわかりません)、ManualResetEvent、AutoResetEvent、または各プロセスで待機スレッドを犠牲にする場合は Mutex)、またはLinux のシグナルです。

于 2009-03-24T11:49:30.520 に答える
1

同じマシン上にある場合、最も簡単な方法は、名前付きパイプ、read() をブロックする「プレーヤー」、DB を変更するたびにトークンをパイプに入れる「エディター」を用意することです。

于 2009-03-24T11:56:09.410 に答える