1

假设我从数据库中检索到对象 A,现在它处于分离状态。数据库中对应于对象 A 的行被外部更新。有没有办法通知我的应用程序对象 A 不再是最新的并且可能会自动刷新?也许数据库上的触发器可以为 Hibernate 创建一个事件?

4

2 回答 2

4

Hibernate 不支持这种情况,因为它旨在用于客户端-服务器应用程序,其中仅存在一个 hibernate 实例,在服务器上运行,并且具有对数据库的独占访问权限。

Hibernate 应该为服务器应用程序提供持久性,并且客户端应该与该服务器应用程序而不是直接与数据库通信,因此所有更新都由服务器应用程序启动,并且它们通过单个 hibernate 实例访问数据库,因此不能有外部更新,并且唯一的 hibernate 实例可以完全控制一切。

当然,将数据库用作服务器是很诱人的,因为它可以使您不必开发自己的客户端-服务器软件。在这种情况下,每个客户端都将运行自己的休眠实例,并且这些实例中的每一个都将直接与数据库对话。然后,问题是您必须以某种方式说服 hibernate 的每个实例查看其他实例对数据库所做的更改。这似乎是一项艰巨的任务,但又一次节省了巨大的成本,(不必编写自己的客户端-服务器软件,在它们之间使用自己的通信协议,)所以值得一试,对吧?

好吧,我以这种方式实现了一个应用程序,我开始后悔了:它笨重、有缺陷,而且性能很差。

但是,如果您真的想尝试一下,这里是如何做到的:

每个客户端都需要通过向“change_log”表中添加行来记录它所做的每一个更改,并且它需要通过查找出现在更改日志表中的新记录来检测其他客户端所做的更改。

对于更改记录,使用hibernate拦截器检测本地客户端对数据库所做的更改,并将每次更改记录在更改日志表中。更改日志的每一行都需要有一个自动递增的 id、更改实体的类名称、实体的 id(数据库键)和事件类型:添加、修改或删除。(当然,您不关心拦截器支持的第四类事件,即行加载。)请注意,您必须为此使用良好的旧 JDBC,因为无法从拦截器回调中重新进入休眠状态。

对于更改检测,运行一个单独的线程来轮询更改日志表的更改。它需要做的就是记住它看到的最后一个更改日志行的 id,并不断询问数据库是否有任何 id 高于此的行。(不要为此使用客户端发布的时间戳,因为客户端时钟中不可避免的微小差异会造成严重破坏。数据库发布的时间戳可能有效,但使用数据库自​​动递增的整数 id 更简单。)当然,你也需要在这里使用 JDBC,因为 hibernate 永远不会告诉你任何行已经添加到更改日志中:记住,hibernate 的印象是整个数据库都属于它,所以它不考虑其他人可能已向其中添加行的可能性。

更改检测线程应该生成事件并以某种方式将它们传递给休眠状态所在的主线程。这意味着您的主线程必须运行一些事件循环,或者定期调用一些滴答机制。一旦你的主线程接收到一个变化检测事件,它会根据事件的类型采取行动:当一个实体被添加时,它告诉 hibernate 加载它,当一个记录被删除时它告诉 hibernate 忘记它,当一个记录更新它告诉休眠刷新它。

就个人而言,我无法说服 hibernate 刷新单个实体,因此我在每次更改检测时都完全刷新 hibernate,这导致性能非常差。我将在下个月解决这个问题,我担心解决它的方法是摆脱休眠。

于 2014-11-22T13:13:09.160 回答
1

我认为 Hibernate 中没有任何东西可以帮助你解决这个问题,所以它只是你能想出的任何东西。您必须跟踪所有实例及其所在位置,以便知道将事件发送到何处。您可以使用Hibernate 拦截器或侦听器来找出特定实体何时更新。

处理冲突更新的典型方法是使用基于版本检查的乐观锁定,并在 Hibernate 参考指南的“乐观并发控制”下进行了广泛讨论。

于 2013-03-20T03:49:46.697 回答