假设我已经从数据库中检索到对象A,现在它处于分离状态。数据库中对应于对象A的行在外部更新。有没有办法通知我的应用程序对象A不再是最新的,也许会自动刷新?也许在数据库上可能会为Hibernate创建一个事件的触发器?当外部改变检索到的对象时,Hibernate会创建通知吗?
回答
我不认为在Hibernate中有什么可以帮助你很多,所以它只是你能想到的任何东西。你必须跟踪所有的实例和它们在哪里,所以你知道在哪里发送事件。您可以使用Hibernate Interceptor or Listener找出特定实体何时更新。
处理冲突更新的典型方法是基于版本检查的乐观锁定,在Hibernate参考指南中的"Optimistic concurrency control"下进行了广泛讨论。
对于这种情况,Hibernate没有支持,因为它意味着在只存在一个在服务器上运行的hibernate实例并且拥有对数据库的独占访问权限的客户端 - 服务器应用程序中使用。
Hibernate应该为服务器应用程序提供持久性,并且客户端应该与该服务器应用程序对话,而不是直接与数据库对话,因此所有更新都由服务器应用程序启动,并且它们通过单个实例休眠到数据库,所以不会有外部更新,并且休眠的唯一实例可以完全控制一切。
当然,使用数据库作为服务器是诱人的,因为它可以使您不必开发自己的客户端服务器软件。在这种情况下,每个客户端都会运行自己的hibernate实例,并且每个实例都会直接与数据库进行通信。然后,问题是你必须以某种方式说服每个hibernate实例来查看其他实例对数据库所做的更改。这似乎是一项艰巨的任务,但节省的成本又很大,(不必编写自己的客户端 - 服务器软件,以及它们之间的自己的通信协议),所以它可能值得一试,对吗?
那么,我已经用这种方式实现了一个应用程序,我后悔了:它笨重,有问题,并且性能很差。
但是,如果你真的想也试试看,这里是如何做到这一点:
每个客户端都需要记录每一个变化,它使得通过增加行到“change_log”表,它将需要通过查找出现在更改日志表中的新记录来检测其他客户端所做的更改。
对于更改记录,使用hibernate拦截器来检测本地客户端对数据库所做的更改,并记录更改日志表中的每个更改。更改日志的每一行都需要具有自动递增的ID,更改后的实体的类名称,实体的ID(数据库键)以及事件的类型:添加,修改或删除。 (当然,你不关心拦截器支持的第四种类型的事件,行加载。)注意,你将不得不使用良好的旧JDBC来执行此操作,因为hibernate不能从拦截器回调中重新输入。
对于更改检测,运行一个单独的线程,轮询更改日志表以查找更改。它所需要做的就是记住它所看到的最后一个更改日志行的标识,并不断询问数据库是否有任何id高于该行的行。 (不要使用客户端发布的时间戳,因为客户端时钟中不可避免的细微差异将导致严重破坏。数据库发布的时间戳可能工作,但使用由数据库自动递增的整数ID更简单。)当然,您也需要在这里使用JDBC,因为hibernate永远不会告诉您任何行已添加到更改日志:记住,hibernate是整个数据库属于它的印象,所以它没有考虑别人可能已经添加了行的可能性。这实际上是我们在这里试图解决的问题。
更改检测线程应该生成事件并以某种方式将它们传递到您的主线程,即休眠状态。这意味着你的主线程必须有一些事件循环运行,或者定期调用一些滴答机制。一旦你的主线程收到一个变化检测事件,它就会根据事件的类型采取行动:当一个实体被添加时,它告诉hibernate加载它,当一个记录被删除时,它告诉hibernate忘记它,并且当一条记录更新它告诉休眠以刷新它。个人而言,我还没有能够说服hibernate刷新一个实体,所以我已经完全冲洗每一次变化检测的休眠,这导致了非常差的性能。我将在接下来的一个月里解决这个问题,我担心解决这个问题的方法是摆脱冬眠。
- 1. 更改域对象的通知(Hibernate/Java)
- 2. 仅当CoreData对象发生更改时才会通知?
- 3. LINQ to SQL - 检索对象,修改SubmitChanges()创建新对象
- 4. WPF:绑定到对象的属性;当对象改变时会发生什么?
- 5. 当对象被创建时
- 6. Hibernate创建重复对象
- 7. 从注释创建表时,Hibernate不会创建索引
- 8. 时通知一个活动的规模不会改变,当它改变
- 9. 为外部对象创建一个DataContract
- 10. 当使用CGLIB创建对象时,发送对象到EJB变为空
- 11. ModelMapper会创建中间对象吗?
- 12. 当通过反射创建接口时将对象投射到对象
- 13. Hibernate + Spring MVC:外部对象库
- 14. Hibernate能看到JVM外部的变化吗?
- 15. Notification.Builder不会创建通知
- 16. 当Firebase数据库更改值时创建推送通知
- 17. Hibernate标准加载对象,会使对象变成持久性的吗?
- 18. 当对象超出范围/得到无效时收到通知
- 19. 会在循环内部/外部声明变量会改变性能吗?
- 20. 当启动另一个对话框时,App.Current.MainWindow会改变吗?
- 21. 创建Hibernate对象的选择
- 22. 知道对象的类名时创建对象的问题
- 23. 通过对比另外两个JSON创建JSON对象对象
- 24. 当从数据库中检索父对象时包含内部嵌套对象
- 25. 在知道C#中部分类名时动态创建对象
- 26. 什么是在Servlet内部/外部创建的对象的生命周期?会话过期时,该对象会死吗?
- 27. 交叉引用的JS对象变量当创建对象
- 28. 通过url检索对象
- 29. 在主方法外部创建对象时出现stackoverflow错误
- 30. 在创建对象时返回除对象之外的东西
谢谢你的帮助,瑞恩!我的印象是,Interceptor和Event只涉及Hibernate范围内的动作。我也知道Hibernate可以处理冲突,但我不知道外部应用程序如何修改我已与之交互的表(在本例中不调用flush方法),我该如何通知我的应用程序。我不确定这个特性是否存在于Hibernate中,但我正试图找到解决这个问题的方法。 – 2013-03-20 19:37:47
你对拦截器和听众是正确的。我不明白你的意思是你的应用程序之外的更新。我很确定你不会从Hibernate那里获得任何帮助。我不知道任何现有的工具可以帮助,但我对处理这样的情况知之甚少,因为我自己从来没有必要处理这种情况。 – 2013-03-21 01:20:24