1

我正在从事一个项目,该项目正在从概念验证过渡到值得试点项目的东西。这一开发阶段的关键改进之一是从当前的“持久性”机制(使用保存在内存中并定期转储到文件中的哈希表)转向更传统的数据库后端。

应用程序本身的设计考虑了ReSTful原则。它使用 Jersey 提供对资源的访问,使用 jQuery 向用户呈现这些资源并启用基本交互(创建、更新、删除)。很直接。

我过去曾成功使用 JPA 和 Hibernate 将服务器端状态持久保存在关系数据库中,因此在这种情况下,这似乎是一个自然的选择。通过对模型实体进行一些小的更改,我能够在合理的时间内完成基本的读取、创建和删除操作。然而,更新操作被证明更加困难。

在用户修改资源几秒钟后,应用程序的客户端部分会自动将更改发送到服务器。此外,还有一个“保存并关闭”按钮,用户可以在返回主页之前立即将最新版本的资源发送到服务器。

我的第一个问题是如何使用来自客户端的非托管对象更新数据库中的托管实体。由于发送到客户端的数据故意省略了数据库键,这有点乏味,因为它归结为将非托管对象中的元素显式“合并”到 Hibernate 对象中。这不是我的问题,但如果有人知道一种优雅的方式来做到这一点,我很想听听。

我的第二个问题,也是这篇文章的目标,发生在我按下“保存并关闭”按钮的同时,我之前提到的自动保存操作正在进行。通常,我得到一个乐观锁定异常。这是因为第二个更新操作正在一个单独的线程中处理,而第一个更新操作仍在处理中。

该资源具有每次处理更新时设置的“更新”时间戳,因此每次都可以保证对数据库的更新,即使没有任何更改。这本身可能是一个问题,但即使在我修复它之后,仍然有一个“机会之窗”,用户可以在自动保存过程中进行修改并将其发送到服务器,从而触发同样的问题.

我能想到的解决此问题的最简单方法是重新编写一些客户端 Javascript,以确保该客户端在任何时间点都只有一个未完成的“更新”操作。(请注意,如果不同的客户端碰巧同时更新相同的资源,乐观锁定异常是完全可以的。)但是,我担心在客户端上强制执行此限制可能会偏离 ReST 的精神。期望给定客户端在 ReSTful 应用程序中的任何时间点对特定资源的未完成“更新”(PUT)请求不超过一个是否合理?

这似乎是一个相当普遍的情况,但我无法找到关于如何最好地处理它的明确答案。我考虑和放弃的其他想法包括以某种方式序列化来自同一客户端的请求(可能基于 HTTP 会话),以便按顺序处理它们,为 JPA/Hibernate 工作线程实现更新“队列”,并插入新的“版本”的资源,同时跟踪最新的而不是更新任何单个记录。

有什么想法吗?客户端的“一次一个未完成的更新”限制是否合理,还是有更好的方法?

4

2 回答 2

0

我的第一个问题是如何使用来自客户端的非托管对象更新数据库中的托管实体。由于发送到客户端的数据故意省略了数据库键,这有点乏味,因为它归结为将非托管对象中的元素显式“合并”到 Hibernate 对象中。这不是我的问题,但如果有人知道一种优雅的方式来做到这一点,我很想听听。

您应该将 id 包含在客户端发送的资源中,或者使用 PUT(例如PUT /object/{objectId})。然后你不需要合并,只需“替换”。我更喜欢总是返回并期待完整的资源。它避免了令人讨厌的合并。

我的第二个问题,也是这篇文章的目标,发生在我按下“保存并关闭”按钮的同时,我之前提到的自动保存操作正在进行。通常,我得到一个乐观锁定异常。这是因为第二个更新操作正在一个单独的线程中处理,而第一个更新操作仍在处理中。

正如您所提到的,您可以通过 JavaScript 在客户端执行此操作。您可以引入“脏”标志,并且自动保存或保存关闭按钮仅在设置“脏”标志时才向服务器发送请求。当用户更改某些内容时,会切换“脏”标志。我不会让服务器序列化请求,这会使事情复杂化。

[...] 但是,我担心将这种限制强加给客户端可能会偏离 ReST 的精神。期望给定客户端在 ReSTful 应用程序中的任何时间点对特定资源的未完成“更新”(PUT)请求不超过一个是否合理?

REST 的一些精神是解耦东西,客户端可以很好地决定何时进行 CRUD 操作。

顺便说一句:有一个很棒的前端 java-script 框架与 REST apis 配合得很好:extJS。它对我们的内部应用程序很有效(由于 extJS 风格的外观和感觉,我不会使用 extJS 做一个公共网站)。

于 2010-08-17T18:04:38.267 回答
0

我遇到了客户端同时对同一 URI 执行同时 PUT 操作的相同问题。客户这样做是没有意义的,但我认为您不会找到任何硬文档说它被禁止或任何程度的 RESTful。事实上,服务器除了序列化它们并在发生乐观并发时抱怨它之外什么也做不了。一个表现良好的客户端会明智地通过同步每个资源上的所有操作来避免这些,甚至是像 GET 或 HEAD 这样的安全操作,这样你就不会用过时的数据污染你的缓存。

于 2010-08-17T19:02:41.427 回答