简体   繁体   English

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

[英]Session management using Hibernate in a *multi-threaded* Swing application

I'm currently working on a (rather large) pet project of mine , a Swing application that by it's very nature needs to be multi-threaded. 我正在研究我的一个(相当大的)宠物项目,一个Swing应用程序,它本质上需要多线程。 Almost all user interactions might fetch data from some remote servers over the internet , since I neither control these servers nor the internet itself, long response times are thus inevitable. 几乎所有用户交互都可能通过互联网从某些远程服务器获取数据,因为我既不控制这些服务器也不控制互联网本身,因此长时间的响应时间是不可避免的。 A Swing UI obviously cannot repaint itself while the EDT is busy so all remote server calls need to be executed by background thread(s). 当EDT繁忙时,Swing UI显然无法重绘自身,因此所有远程服务器调用都需要由后台线程执行。

My problem: 我的问题:

Data fetched by the background threads gets 'enriched' with data from a local (in-memory) database (remote server returns IDs/references to data in the local database). 后台线程获取的数据使用来自本地(内存)数据库的数据“丰富”(远程服务器返回ID /对本地数据库中数据的引用)。 This data later eventually gets passed to the EDT where it becomes part of the view model. 这些数据最终会传递到EDT,在那里它成为视图模型的一部分。 Some entities are not completely initialized at this point (lazy-fetching enabled) so the user might trigger lazy-fetching by eg scrolling in a JTable. 此时某些实体未完全初始化(启用了延迟抓取),因此用户可能通过例如在JTable中滚动来触发延迟抓取。 Since the hibernate session is already closed this will trigger a LazyInitializationException. 由于hibernate会话已经关闭,这将触发LazyInitializationException。 I can't know when lazy-fetching might be triggered by the user so creating a session on demand/attaching the detached object will not work here. 我不知道什么时候用户可能会触发延迟抓取,因此按需创建会话/附加分离的对象在这里不起作用。

I 'solved' this problem by: 我通过以下方式解决了这个问题:

  • using a single (synchronized , since Session instances are not thread-safe) Session for the whole application 使用单个(同步,因为Session实例不是线程安全的)整个应用程序的Session
  • disabling lazy-fetching completely 完全禁用延迟抓取

While this works, the application's performance has suffered greatly (sometimes being close to unusable). 虽然这有效,但应用程序的性能却遭受了很大的损失(有时几乎无法使用)。 The slowdown is mainly caused by the large number of objects that are now fetched by each query. 减速主要是由每个查询现在提取的大量对象引起的。

I'm currently thinking about changing the application's design to 'Session-per-thread' and migrating all entities fetched by non-EDT threads to the EDT thread's Session (similar to this posting on the Hibernate forums ). 我目前正在考虑将应用程序的设计更改为“每个线程的会话”,并将非EDT线程提取的所有实体迁移到EDT线程的Session(类似于Hibernate论坛上的这个帖子 )。

Side-note: Any problems related to database updates do not apply since all database entities are read-only (reference data). 附注:与数据库更新相关的任何问题都不适用,因为所有数据库实体都是只读的(参考数据)。

Any other ideas on how to use Hibernate with lazy-loading in this scenario ? 关于如何在这种情况下使用延迟加载Hibernate的任何其他想法?

Don't expose the Session itself in your data API. 不要在数据API中公开Session本身。 You can still do it lazily, just make sure that the hydration is being done from the 'data' thread each time. 你仍然可以做到这一点懒洋洋地,只要确保水化正在 “数据”线程每次完成。 You could use a block (runnable or some kind of command class is probably the best Java can do for you here unfortunately) that's wrapped by code that performs the load async from the 'data' thread. 你可以使用一个块(可运行的或某种类型的命令类可能是最好的Java在这里可以为你做的),它被包含在执行来自'data'线程的加载异步的代码所包含。 When you're in UI code, (on the UI thread of course) field some kind of a 'data is ready' event that is posted by the data service. 当您处于UI代码中时(当然在UI线程上)字段中,某种类型的“数据就绪”事件由数据服务发布。 You can then get the data from the event use in the UI. 然后,您可以从UI中的事件使用中获取数据。

You could look have a look at Ebean ORM . 你可以看看Ebean ORM It is session-less and lazy loading just works. 这是无会话和延迟加载只是工作。 This doesn't answer your question but really proposes an alternative. 这不能回答你的问题,但确实提出了另一种选择。

I know Ebean has built in support for asynchronous query execution which may also be interesting for your scenario. 我知道Ebean已经内置了对异步查询执行的支持,这对你的场景也很有用。

Maybe worth a look. 也许值得一看。

  • Rob. 抢。

There are two distinct problems, that should get resolved seperately: 有两个明显的问题,应该单独解决:

  1. Handling of Hibernate Sessions in Swing Applications. 在Swing应用程序中处理Hibernate会话。 Let me recommend my own article, regarding this problem: http://blog.schauderhaft.de/2008/09/28/hibernate-sessions-in-two-tier-rich-client-applications/ 让我推荐一篇关于这个问题的文章: http//blog.schauderhaft.de/2008/09/28/hibernate-sessions-in-two-tier-rich-client-applications/

The basic idea is to have a session for every frame, excluding modal frames which use the session of the spawning frame. 基本思想是为每个帧建立一个会话,不包括使用产卵帧会话的模态帧。 It is not easy but it works. 这不容易,但它的工作原理。 Meaning, you won't get any LLEs anymore. 意思是,你不会再获得任何LLE了。

  1. How to get your GUI thread separated from the back end. 如何将GUI线程与后端分开。

I recommend to keep the hibernate objects strictly on the back end thread they originate from. 我建议将hibernate对象严格保留在它们源自的后端线程上。 Only give wrapper objects to the ETD. 仅向ETD提供包装器对象。 If these wrapper objects are asked for a value, they create a request which gets passed to the backend thread, which eventually will return the value. 如果要求这些包装器对象提供值,它们会创建一个请求,该请求将传递给后端线程,最终将返回该值。

I'd envision three kinds of wrapper Implementations: 我想到了三种包装器实现:

Async : requests the value, and gets notified when the value is available. Async :请求值,并在值可用时收到通知。 It would return immediately with some dummy value. 它会立即返回一些虚拟值。 On notification it will fire a PropertyChange event iO to inform the GUI about the 'changed' value (changed from unknown to a real value). 在通知时,它将触发PropertyChange事件iO以通知GUI有关“已更改”值(从未知值更改为实际值)。

Sync : requests the value and waits for it to be available. 同步 :请求值并等待它可用。

Timed : a mixture between the two, waiting for a short time (0.01) seconds, before returning. 定时 :两者之间的混合,等待很短的时间(0.01)秒,然后返回。 This would avoid plenty change events, compared to the async version. 与异步版本相比,这可以避免大量的更改事件。

As a basis for these wrappers a recommend the ValueModel of the JGoodies Binding library: http://www.jgoodies.com/downloads/libraries.html 作为这些包装器的基础,建议使用JGoodies Binding库的ValueModel: http ://www.jgoodies.com/downloads/libraries.html

Obviously You need to take care that any action is only performed on actually loaded values, but since you don't plan on doing updates this shouldn't be to much of an issue. 显然,您需要注意任何操作仅对实际加载的值执行,但由于您不打算进行更新,因此这不应该是一个很大的问题。

Let me end with a warning: I have thought about it a lot, but never actually tried it, so move with care. 让我以警告结束:我已经考虑了很多,但从未真正尝试过,所以谨慎行事。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM