14

複数のモバイル クライアントと Web ベースのサーバー アプリケーションを含む分散アプリケーションを実装します。そのため、各クライアントとサーバーもテーブル エントリを生成できます。したがって、すべての参加者に対して一意の主キーが必要であり、キーをオフラインで生成できるようにしたいと考えています。

分散環境で使用している主キーを生成するための最良の方法は何ですか? 同様の質問については、SQLite と Azure SQL データベースを中央ストアとして使用するオンライン/オフラインのマルチクライアント モバイル アプリケーションに最適な主キー戦略は何ですか?を参照してください。

UUID キーの生成がそのシナリオに適したアプローチであることは承知していますが、Android プラットフォームで提案されているように、_id という名前と長いタイプのキーに固執したいと考えています。

デバイス(サーバーもデバイス)IDとローカルIDの複合IDを持ちたくありません。サーバーは特定のクライアントのエントリを生成できる必要があるため、このアプローチはうまく機能しません。その場合、サーバーでもデバイス ID を使用する必要があります。

したがって、私の現在のお気に入りは、長いデータ型でキーを作成することです (以前に別のプロジェクトでこれを行いました)。ハイ/ローアプローチを使用すると思います(たとえば、こちらの ハイ/ロー アルゴリズムとは?を参照してください)。

  • サーバーから生成されたクライアント ID (例: ~28 ビット)
  • 低い値 (例: ~ 4 ビット) クライアントでインクリメントされ、永続化されない
  • 高い値 (例: ~ 32 ビット) クライアントでインクリメントされ、クライアントでのみ永続化されます

クライアント ID は、モバイル アプリケーションの最初の起動時にサーバーから取得する必要があります。したがって、最初の起動にはネットワーク接続が必要です。これは、このアプローチの欠点かもしれません。デバイスにクライアント ID がある場合、ネットワーク接続なしでキーを生成できます。

通常、上位 ID はデータベース全体で一意の値です。ユーザーがアプリケーションをアンインストールして再度インストールすると、私は彼を新しいクライアントとして扱い、新しいクライアント ID を与える必要があります。そうしないと、サーバーに現在の高IDを保存して、紛失または再インストール時に復元できるようにする必要があります-努力する価値はありません。

Androidで高いIDを取得するための最良の方法は何ですか? 自動インクリメント キーは解決策ではありません。ジェネレータ関数のようなものが必要です。また、独自のトランザクション内で実行する必要があります (「ユーザー」トランザクションではありません)。Androidでそのアプローチを経験した人はいますか?誰かが私を正しい方向に向けることができますか? (私はこの答えしか見つけませんでした)。

マルチ クライアント アプリケーション (オンラインおよびオフライン) で使用している主要な戦略は何ですか?

4

5 に答える 5

2

この質問に対して 2 つの報奨金を提供しましたが、探している答えが見つかりませんでした。しかし、私は最善の解決策について考えるのに時間を費やしましたが、おそらく質問は十分にオープンではなく、私が考えていた解決策に焦点を当てていました.

しかし、利用可能なさまざまな戦略がたくさんあります。現在 (2 回目の報奨金の後)、答えるべき最初の質問は、分散環境でどのデータ モデルを使用しているかということだと思います。あなたが持っているかもしれません

  1. クライアントとサーバーの同じ (またはサブセット) データ モデル
  2. 異なるクライアント データ モデルとサーバー データ モデル

1) と答えた場合、主要な戦略として次の中から選択できます。

  • GUID の使用
  • 私のアプローチを使用して 高/低
  • @ user3603546が提案したようにキーをマッピングする

2) と答えると、次のことだけが頭に浮かびます。

  • 複合 ID

私は複合IDが好きではありませんでしたが、それについて考えると(とにかく複合IDとは呼ばないでください)、解決策になる可能性があります。次に、このソリューションをスケッチします。

用語集:

  • <client key> ... クライアント側で生成された主キーなので、クライアントが実装を選択します (Android の long _id)
  • <server key> ... サーバー側で生成された主キーなので、サーバーが実装を選択します
  • <client id> … クライアントを識別するためのID
  • <device id> ... デバイスを識別するためのIDで、クライアントとデバイスは1対nの関係にあります

解決:

  • クライアント データ モデルとサーバー データ モデルがある場合にのみ使用します。
  • クライアントデータモデルにはフィールドがあります
    • <クライアント キー> プライマリ キー
    • <サーバー キー> null 許容データ フィールド
  • サーバーデータモデルにはフィールドがあります
    • <server key> を主キーとして
    • <クライアント キー> null 許容データ フィールド
    • クライアントを識別するための必須データ フィールドとしての <client id>
  • サーバーからクライアントに同期する場合、クライアントで不足している <client key> を生成し、エントリをダーティとしてマークします (その日の終わりにクライアント ID がサーバーに送信されるようにします)。
  • クライアントからサーバーに同期するときは、保存する前にサーバー上で不足している <server key> を生成します
  • クライアントとサーバーのデータ モデル間のマッピングは、 dozerOrikaなどの特殊なフレームワークで処理できますが、マッピングを実行するときにキー生成を統合する必要があります。

私は常にサーバー データ モデルの用語で考えていたので、このソリューションは好きではありませんでした。サーバー上にのみ存在するエンティティがあり、これらのエンティティをクライアント上に作成したいと常に思っていましたが、これは不可能です。しかし、クライアントデータモデルで考えると、エンティティが 1 つある場合があります。サーバー上で 2 つのエンティティ (製品と ClientProduct) になる製品。

于 2014-06-03T16:12:46.757 に答える
2

これは答えよりも多くの質問です...

すべての ID を自動生成できれば作業が簡単になります。そのため、サーバーから ID をフェッチする必要がなく、接続しているかどうかを心配する必要がありません。「Androidプラットフォームで提案されているように」長いものを使用するため、一般的なアプローチ(UUIDまたはANDROID_ID)を使用できないと述べています。

Android が SQLite テーブルに long _id 主キーがあると想定しているという事実に言及していますか?

サーバーでデータストアまたは SQL データベースを使用していますか?

階層キーを持つデータストア (Google データストアなど) を使用している場合、クライアント ID として UUID/ANDROID_ID を使用し、データ項目 ID として long を使用するとどうなりますか。次に、クライアントでは long を保存するだけで、サーバーではエンティティが UUID/long のキーパスで保存されます。

「高IDはデータベース全体で一意の値でなければならない」と書いているのはなぜですか? クライアント ID が先頭に追加されているため、ローカル データベース上で一意でなければならないということでしょうか?

ユーザーがアプリをアンインストールして再インストールできるという問題を処理するには、「現在の上位 ID をサーバーに保存して、紛失または再インストール時に復元できるようにする」という考えを追求してみませんか。最初の実行時にクライアント ID を取得することを既に計画しているので (それを取得するまで ID を割り当てることはできません)、サーバーに次の利用可能な上位 ID を要求することもできます。

あなたのエンティティには、ハイ ID の 32 ビット ハッシュをそのマテリアルから生成できるような、他のキー マテリアルがありますか? 高IDが特定のクライアントで一意である必要があるだけであると仮定すると(そして、クライアントに膨大な数のエンティティがないと仮定すると)、適切なキーマテリアルがあり、ハッシュを使用すると、衝突は発生しないと思います衝突を最小限に抑える機能。

于 2013-04-28T15:07:30.473 に答える
2

私の経験から:デバイスではローカル ID を使用し、サーバーでは別の ID を使用します。ネットワーク経由でデータを通信するたびに、一方から他方に変換します。これにより、実際にプロセスが明確になり、デバッグが容易になります。変換ルーチンは小さいままで、十分に分離されており、アプリケーション アーキテクチャの自然な要素を表しています。とにかく、ネットワーク上を移動するデータは比較的小さいと予想され、ID 変換は大きなオーバーヘッドにはなりません。また、モバイル デバイスに保持されているデータの量は、おそらく少量です (大部分はサーバー上にあります)。

シンプルなテーブルlocal_ID <-> server_IDを使用して、デバイスで変換を行うことを提案します。サーバーは 1 つの手順のみを提供する必要があります。キーのバッチ、たとえば 444 個の新しいキーを生成します。おそらく、モバイル デバイスはローカル ID に割り当て、server_ID のみを使用してサーバーにデータを送信します。変換テーブルは、未使用の ID をときどきパージすることができ、ローカル ID を再利用できます。32 ビット整数で十分です。

動機

テーブルは小さいままで、実装はネイティブ デバイス アーキテクチャに対して最適なままであり、他の場所での予測できないアーキテクチャの変更から隔離されています。また、すべてのデータが通過するデバッグとトレースに適したポイントがあります。

データ ファイルの保存と読み込みのたびにすべての ID を再生成するアプリケーションを用意しました。これは予想外にシンプルで高速で、ID スペースの最適化や統合などのエレガントな他の可能性を切り開きました。

あなたの場合、クライアント アプリケーションへの最小限の変更でサーバー テクノロジを変更できます。いずれにしてもクライアントはオフラインで操作できるため、ほとんどの機能でローカル ID のみを使用できます。同期モジュールのみがサーバー ID を取得して変換します。

于 2014-06-03T07:32:42.133 に答える
1

サーバーと通信するまで、クライアントで生成しているキーがサーバー DB で一意であることを確実に知る方法はありません。

クライアント側でレコードを作成する前に、サーバーと事前に通信する場合は、サーバーで一連のキーを予約できます。たとえば、サーバーは 10,000 個のバッチでキーを配布できます。クライアントはサーバーと通信し、利用可能なキーの次のバッチ (たとえば 60,000) の開始を予約します。その後、クライアントは 60,000 から 69,999 までの ID を持つレコードを自由に作成できます。クライアントがキーを使い果たしたら、新しい範囲のキーを要求する必要があります。すべてのクライアントとサーバーがこのようにキーを予約している場合、生成されたすべての ID はサーバーのデータベース内で一意になります。

サーバーと通信する前にクライアント側でレコードを作成する場合、サーバーから予約された範囲を取得したら、それらの ID をその範囲内に収まるように修正してから、それらのレコードをサーバーに同期する必要があります。 .

キーにクライアント ID を含めようとしている理由がわかりません。サーバーは高い値を割り当てており、クライアントで生成された一意のキーを取得するにはこれで十分です。

于 2014-05-30T15:27:09.287 に答える
1

私がこれを理解できるかどうか見てみましょう: デバイスに固有の 32 ビット番号が必要ですか? Ok:

  1. ランダムに、または現在のナノタイムをハッシュして番号を作成します。これにより、かなりユニークな文字列がそのまま取得されます。
  2. 次に、その番号がすでに使用されているかどうかをサーバーに問い合わせます。ある場合は、番号をもう一度生成して、もう一度尋ねます。

ナノタイムをハッシュする場合、同じ数値を取得することは事実上不可能です (完全に不可能というわけではなく、衝突抵抗は衝突防止ではありません)。文字列の残りの部分を考えると、それは完全に一意になります。このメソッドは、実際にサーバーを使用する必要があるまで、サーバーとの対話を必要としません。クライアントが最初の起動時に接続されていないとします。番号を生成して保存し、接続したら、何かが起こる前に、デバイスが存在するかどうかを確認します。もしそうなら、最初からやり直してください。そうすれば、真に一意のデバイス ID を取得できます。

于 2013-07-02T18:07:08.747 に答える