我正在开展一个项目,该项目正在从概念验证过渡到一个值得试点的项目。这一发展阶段的一个关键改进是摆脱目前的“持久性”机制,该机制使用内存中保存的哈希表并定期转储到文件中,转移到更传统的数据库后端。
应用程序本身的设计考虑了ReSTful原则。它使用Jersey来提供对资源的访问,并使用jQuery向用户呈现这些资源并启用基本交互(创建,更新,删除)。很直接。
我过去曾成功使用JPA和Hibernate来保持关系数据库中的服务器端状态,因此在这种情况下它似乎是一个自然的选择。通过对模型实体进行一些小的更改,我能够在合理的时间内完成基本的读取,创建和删除操作。但是,更新操作更加困难。
应用程序的客户端部分会在用户修改资源后几秒钟自动将更改发送到服务器。此外,还有一个“保存并关闭”按钮,用户可以在返回主页之前立即按下该按钮将最新版本的资源发送到服务器。
我的第一个问题是如何使用来自客户端的非托管对象从数据库更新托管实体。由于发送给客户端的数据故意省略数据库密钥,因此它有点单调乏味,因为它明确地将非托管对象中的元素“合并”到Hibernate对象中。这不是我的问题,但如果有人知道这样做的优雅方式,我会非常有兴趣听到它。
当我在前面提到的自动保存操作正在进行的同时按下“保存并关闭”按钮时,出现了我的第二个问题,以及这篇文章的目标。通常情况下,我得到一个乐观的锁定异常。这是因为第二个更新操作正在一个单独的线程中处理,而第一个仍在处理中。
资源具有“更新”时间戳,每次处理更新时都会设置该时间戳,因此即使没有任何更改,每次都可以保证对数据库的更新。这本身可能是一个问题,但即使在我修复它之后,仍然存在一个“机会之窗”,用户可以在进行自动保存的同时进行修改并将其发送到服务器,从而触发相同的问题
我能想到解决这个问题的最简单的方法是重做一些客户端Javascript,以确保在任何时间点只有一个来自该客户端的未完成的“更新”操作。 (请注意,如果不同的客户端碰巧同时更新同一资源,则乐观锁定异常完全没问题。)但是,我担心在客户端强制执行此限制可能会偏离来自ReST的精神。期望给定客户端在ReSTful应用程序中的任何时间点对特定资源的不超过一个未完成的“更新”(PUT)请求是否合理?
这似乎是一种相当常见的情况,但我无法找到关于如何最好地处理它的明确答案。我考虑和丢弃的其他想法包括以某种方式序列化来自同一客户端的请求(可能基于HTTP会话),以便按顺序处理它们,为JPA / Hibernate工作线程实现更新的“队列”,并插入新的“资源的“版本”,同时跟踪最新的,而不是更新任何单个记录。
有什么想法?客户端的“一次一个未完成的更新”限制是否合理,还是有更好的方法?
答案 0 :(得分:0)
我的第一个问题是如何使用来自客户端的非托管对象从数据库更新托管实体。由于发送给客户端的数据故意省略数据库密钥,因此它有点单调乏味,因为它明确地将非托管对象中的元素“合并”到Hibernate对象中。这不是我的问题,但如果有人知道这样做的优雅方式,我会非常有兴趣听到它。
您应该将id包含在客户端发送的资源中,或者使用PUT(例如PUT /object/{objectId}
)。然后你不需要合并,只需“替换”。我更愿意总是回来并期待完整的资源。它避免了令人讨厌的合并。
当我在前面提到的自动保存操作正在进行的同时按下“保存并关闭”按钮时,出现了我的第二个问题,以及这篇文章的目标。通常情况下,我得到一个乐观的锁定异常。这是因为第二个更新操作正在一个单独的线程中处理,而第一个仍在处理中。
正如您所提到的,您可以通过JavaScript在客户端执行此操作。您可以引入“脏”标志,自动保存或保存关闭按钮仅在设置标志“脏”时向服务器发送请求。当用户改变某些东西时,“脏”标志被切换。我不会让服务器序列化请求,这使事情变得复杂。
[...]然而,我担心强迫客户的这种限制可能会偏离ReST的精神。期望给定客户端在ReSTful应用程序中的任何时间点对特定资源的不超过一个未完成的“更新”(PUT)请求是否合理?
REST的一些精神是解耦东西,客户端可以很好地决定何时进行CRUD操作。
顺便说一句:有一个很棒的前端java脚本框架,它与REST apis非常吻合:extJS。它对我们内部应用程序很有效(我不会因为extJS风格的外观和感觉而使用extJS进行公共网站)。
答案 1 :(得分:0)
我遇到了同样的问题,即客户端同时对同一个URI执行同步PUT操作。对于客户来说这样做是没有意义的,但我认为你不会发现任何硬文件说它被禁止或任何程度的RESTful。实际上,服务器除了序列化它们之外不能做任何事情,并且当它确实发生时抱怨乐观并发。一个表现良好的客户端通过同步每个资源上的所有操作,甚至安全操作(如GET或HEAD)来避免这些操作是明智的,因此您不会使用陈旧数据污染缓存。