GWT RequestFactory 是否支持乐观并发控制的实现?

发布于 2024-12-08 13:30:57 字数 355 浏览 0 评论 0原文

在 GWT 应用程序中,我呈现可由用户编辑的项目。加载和保存项目是通过使用 GWT 请求工厂来执行的。我现在想要实现的是,如果两个用户同时编辑一个项目,则首先保存的用户以乐观并发控制的方式获胜。这意味着当第二个用户保存他的更改时,请求工厂后端会识别出存储在后端的项目的版本或存在状态已更改,因为它已传输到客户端,并且请求工厂/后端会以某种方式阻止项目更新/已保存。

我尝试在用于保存项目的服务方法中实现此功能,但这不起作用,因为请求工厂将刚刚从后端检索到的项目与应用的用户更改一起提交,这意味着这些项目的版本是后端的当前版本并且比较毫无意义。

我可以利用请求工厂处理中的任何钩子来实现请求的行为吗?还有其他想法吗?或者我必须使用 GWT-RPC 来代替......

In a GWT app I present items that can be edited by users. Loading and saving the items is perfomed by using the GWT request factory. What I now want to achive is if two users concurrently edit an item that the user that saves first wins in the fashion of optimistic concurrency control. Meaning that when the second user saves his changes the request factory backend recognizes that the version or presence of the item stored in the backend has changed since it has been transfered to the client and the request factory/backend then somehow prevents the items from being updated/saved.

I tried to implement this in the service method that is used to save the items but this will not work because request factory hands in the items just retrieved from the backend with applied user's changes meaning the versions of these items are the current versions from the backend and a comparison pointless.

Are there any hooks in the request factory processing I coud leverage to achieve the requested behaviour? Any other ideas? Or do I have to use GWT-RPC instead...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

马蹄踏│碎落叶 2024-12-15 13:30:57

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

直到建议的 API 实现为止(EntityLocator,在评论 #1 中,但我不清楚版本信息如何由其重构序列化形式),您必须以某种方式将版本发送回服务器。
正如我在问题中所说,这不能通过简单地在代理中提供版本属性并设置它来完成;但您可以添加另一个属性:获取它总是返回 null (或类似的不存在值),以便在客户端将其设置为“true”的值“版本属性总是会产生更改,这保证了该值将作为“属性差异”的一部分发送到服务器;在服务器端,您可以在setter中处理事情(当RequestFactory应用“属性差异”并调用setter时,如果该值与“true”版本不同,则抛出异常)或在服务中处理事情方法(比较从客户端发送的版本——您可以从与客户端上映射的 getter 不同的 getter 获得该版本,因为该版本必须始终返回 null——与该版本的“true”版本对象,并在以下情况下引发错误不匹配)。

例如:

@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();
      }
   }
}

请注意,我还没有对此进行测试,这是纯粹的理论。

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

Until the proposed API is implemented (EntityLocator, in comment #1, but it's not clear to me how the version info could be reconstructed from its serialized form), you'll have to somehow send the version back to the server.
As I said in the issue, this cannot be done by simply making the version property available in the proxy and setting it; but you could add another property: getting it would always return null (or similar nonexistent value), so that setting it on the client-side to the value of the "true" version property would always produce a change, which guaranties the value will be sent to the server as part of the "property diff"; and on the server-side, you could handle things either in the setter (when RequestFactory applies the "property diff" and calls the setter, if the value is different from the "true" version, then throw an exception) or in the service methods (compare the version sent from the client –which you'd get from a different getter than the one mapped on the client, as that one must always return null– to the "true" version of the object, and raise an error if they don't match).

Something like:

@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();
      }
   }
}

Note that I haven't tested this, this is pure theory.

尹雨沫 2024-12-15 13:30:57

我们想出了另一种在我们的应用程序中实现乐观锁定的解决方法。由于版本无法通过代理本身传递(正如 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 到域对象。

在我们的例子中,我们只跟踪一个实体,因此我们使用一个版本,但该方法可以扩展到多个实体。

We came up with another workaround for optimistic locking in our app. Since the version can't be passed with the proxy itself (as Thomas explained) we are passing it via HTTP GET parameter to the request factory.

On the client:

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

On the server we create a ServiceLayerDecorator and read version from the 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;
  }
}

The advantage is that loadDomainObject() is called before any changes are applied to the domain object by RF.

In our case we're just tracking one entity so we're using one version but approach can be extended to multiple entities.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文