在*多线程* Swing应用程序中使用Hibernate进行会话管理

时间:2009-11-02 23:51:43

标签: java multithreading hibernate swing

我正在研究我的一个(相当大的)宠物项目,一个Swing应用程序,它本质上需要多线程。几乎所有用户交互都可能通过互联网从某些远程服务器获取数据,因为我既不控制这些服务器也不控制互联网本身,因此长时间的响应时间是不可避免的。当EDT繁忙时,Swing UI显然无法自行重绘,因此所有远程服务器调用都需要由后台线程执行。

我的问题:

后台线程获取的数据使用来自本地(内存中)数据库的数据“丰富”(远程服务器返回ID /对本地数据库中数据的引用)。这些数据最终会传递到EDT,在那里它成为视图模型的一部分。此时某些实体未完全初始化(启用了延迟抓取),因此用户可能会触发延迟抓取。在JTable中滚动。由于hibernate会话已经关闭,这将触发LazyInitializationException。我不知道什么时候用户可以触发延迟抓取,因此按需创建会话/附加分离的对象在这里不起作用。

我通过以下方式解决了这个问题:

  • 使用单个(同步,因为会话实例不是线程安全的)整个应用程序的会话
  • 完全禁用延迟抓取

虽然这样可行,但应用程序的性能却遭受了很大的损失(有时几乎无法使用)。减速主要是由每个查询现在提取的大量对象引起的。

我目前正在考虑将应用程序的设计更改为“每个线程的会话数”,并将非EDT线程提取的所有实体迁移到EDT线程的会话(类似于this posting on the Hibernate forums)。

附注:由于所有数据库实体都是只读的(参考数据),因此与数据库更新相关的任何问题都不适用。

在这种情况下如何使用Hibernate 延迟加载的任何其他想法?

3 个答案:

答案 0 :(得分:1)

不要在数据API中公开Session本身。你仍然可以懒惰地做,只需确保每次都从 '数据'线程进行水合作用。你可以使用一个块(可运行的或某种类型的命令类可能是最好的Java在这里可以为你做的),它被包含在执行来自'data'线程的加载异步的代码所包含。当您处于UI代码中时(当然在UI线程上)字段中,某种类型的“数据就绪”事件由数据服务发布。然后,您可以从UI中获取事件使用的数据。

答案 1 :(得分:1)

你可以看看Ebean ORM。这是无会话和延迟加载只是工作。这不能回答你的问题,但确实提出了另一种选择。

我知道Ebean已经内置了对异步查询执行的支持,这对您的场景也很有用。

也许值得一看。

  • 罗布。

答案 2 :(得分:0)

有两个明显的问题,应该单独解决:

  1. 在Swing应用程序中处理Hibernate会话。关于这个问题,我建议我自己的文章:http://blog.schauderhaft.de/2008/09/28/hibernate-sessions-in-two-tier-rich-client-applications/
  2. 基本思想是为每个帧建立一个会话,不包括使用产卵帧会话的模态帧。这不容易,但它的工作原理。意思是,你不会再获得任何LLE了。

    1. 如何将GUI线程与后端分开。
    2. 我建议将hibernate对象严格保留在它们源自的后端线程上。仅向ETD提供包装器对象。如果要求这些包装器对象提供值,它们会创建一个请求,该请求将传递给后端线程,最终将返回该值。

      我设想了三种包装器实现:

      异步:请求该值,并在值可用时收到通知。它会立即返回一些虚拟值。在通知时,它将触发一个PropertyChange事件i.O.通知GUI有关“已更改”的值(从未知值更改为实际值)。

      同步:请求该值并等待其可用。

      定时:两者之间的混合,等待很短的时间(0.01)秒,然后返回。与异步版本相比,这可以避免大量的更改事件。

      作为这些包装器的基础,建议使用JGoodies Binding库的ValueModel:http://www.jgoodies.com/downloads/libraries.html

      显然,您需要注意任何操作仅对实际加载的值执行,但由于您不打算进行更新,因此这不应该是一个大问题。

      让我以警告结束:我已经考虑了很多,但从未真正尝试过,所以请小心行动。