当外部更改检索到的对象时,Hibernate会创建通知吗?

时间:2013-03-20 03:42:17

标签: hibernate events triggers refresh external

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

2 个答案:

答案 0 :(得分:4)

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

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

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

好吧,我已经用这种方式实现了一个应用程序,我后悔了:它很笨拙,错误,性能非常差。

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

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

对于更改记录,使用hibernate拦截器检测本地客户端对数据库所做的更改,并在更改日志表中记录每个更改。更改日志的每一行都需要具有自动递增ID,已更改实体的类名称,实体的id(数据库键)以及事件类型:添加,修改或删除。 (当然你不关心拦截器支持的第四种类型的事件,加载行。)注意你必须使用好的旧JDBC,因为无法从拦截器回调中重新输入hibernate。 / p>

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

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

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

答案 1 :(得分:1)

我认为Hibernate中没有任何东西可以帮助你解决这个问题,所以它只是你想出的任何东西。您必须跟踪所有实例及其位置,以便了解发送事件的位置。您可以使用Hibernate Interceptor or Listener来查找特定实体的更新时间。

处理冲突更新的典型方法是使用基于版本检查的乐观锁定,并在Hibernate参考指南的"Optimistic concurrency control"下广泛讨论。