2

GWT アプリで、ユーザーが編集できるアイテムを提示します。アイテムのロードと保存は、GWT リクエスト ファクトリを使用して実行されます。私が今達成したいのは、2 人のユーザーがアイテムを同時に編集し、最初に保存したユーザーが楽観的同時実行制御の方法で勝つということです。つまり、2 番目のユーザーが変更を保存すると、リクエスト ファクトリ バックエンドは、バックエンドに保存されているアイテムのバージョンまたは存在がクライアントに転送されてから変更されたことを認識し、リクエスト ファクトリ/バックエンドは何らかの方法でアイテムの更新を防止します。 /保存されました。

アイテムを保存するために使用されるサービス メソッドでこれを実装しようとしましたが、リクエスト ファクトリがユーザーの変更を適用してバックエンドから取得したばかりのアイテムを渡すため、これらのアイテムのバージョンはバックエンドからの現在のバージョンであるため、これは機能しません。そして無意味な比較。

要求された動作を実現するために活用できる要求ファクトリ処理にフックはありますか? 他のアイデアはありますか?または、代わりに GWT-RPC を使用する必要がありますか...

4

2 に答える 2

3

いいえ: http://code.google.com/p/google-web-toolkit/issues/detail?id=6046

提案された API が実装されるまで (コメント #1 に記載されていますが、シリアル化されEntityLocatorた形式からバージョン情報を再構築する方法が明確ではありません)、何らかの方法でバージョンをサーバーに送り返す必要があります。 問題で述べたように、これは単純にバージョン プロパティをプロキシで使用可能にして設定するだけでは実行できません。ただし、別のプロパティを追加することもできます。それを取得すると、常に返されます(または同様の存在しない
nullそのため、クライアント側で「true」バージョン プロパティの値に設定すると、常に変更が生じます。これにより、値が「プロパティ差分」の一部としてサーバーに送信されることが保証されます。サーバー側では、セッター (RequestFactory が「プロパティ diff」を適用してセッターを呼び出すとき、値が「真の」バージョンと異なる場合は例外をスローする) またはサービスで物事を処理できます。メソッド (クライアントから送信されたバージョン (クライアントにマップされたものとは異なる getter から取得します。常に返す必要がnullあるため) をオブジェクトの「真の」バージョンと比較し、エラーが発生した場合はエラーを発生させます)一致しません)。

何かのようなもの:

@ProxyFor(MyEntity.class)
interface MyEntityProxy extends EntityProxy {
   String getServerVersion();
   String getClientVersion();
   void setClientVersion(String clientVersion);
   …
}

@Entity
class MyEntity {
   private String clientVersion;
   @Version private String serverVersion;

   public String getServerVersion() { return serverVersion; }
   public String getClientVersion() { return null; }
   public void setClientVersion(String clientVersion) {
      this.clientVersion = clientVersion;
   }

   public void checkVersion() {
      if (Objects.equal(serverVersion, clientVersion)) {
         throw new OptimisticConcurrencyException();
      }
   }
}

私はこれをテストしていないことに注意してください。これは純粋な理論です。

于 2011-10-08T14:03:32.143 に答える
2

アプリの楽観的ロックに対する別の回避策を考え出しました。プロキシ自体でバージョンを渡すことができないため ( Thomas が説明したように)、 HTTP GETパラメーターを介してリクエスト ファクトリに渡します。

クライアントで:

MyRequestFactory factory = GWT.create( MyRequestFactory.class );
RequestTransport transport = new DefaultRequestTransport() {
        @Override
        public String getRequestUrl() {
            return super.getRequestUrl() + "?version=" + getMyVersion();
        }
    };
factory.initialize(new SimpleEventBus(), transport);

サーバー上で ServiceLayerDecorator を作成し、以下からバージョンを読み取りますRequestFactoryServlet.getThreadLocalRequest()

public static class MyServiceLayerDecorator extends ServiceLayerDecorator {
  @Override
  public final <T> T loadDomainObject(final Class<T> clazz, final Object domainId) {
    HttpServletRequest threadLocalRequest = RequestFactoryServlet.getThreadLocalRequest();
    String clientVersion = threadLocalRequest.getParameter("version") );

    T domainObject = super.loadDomainObject(clazz, domainId);
    String serverVersion = ((HasVersion)domainObject).getVersion();

    if ( versionMismatch(serverVersion, clientVersion) )
      report("Version error!");         

    return domainObject;
  }
}

利点は、loadDomainObject()変更が RF によってドメイン オブジェクトに適用される前に呼び出されることです。

この場合、1 つのエンティティを追跡しているだけなので、1 つのバージョンを使用していますが、アプローチは複数のエンティティに拡張できます。

于 2012-05-08T15:26:51.283 に答える