Java桌面-如何将数据库访问与UI线程分离



我最近使用Quartz调度器来运行一些涉及数据库访问的后台进程(例如,报告生成)。现在,这些后台任务在单独的线程中运行。然而,数据库访问是在我的应用程序中的一个中心点完成的,类似

System.err.println("CURRENT THREAD: "+ Thread.currentThread().getName());

打印";"main";,在执行实际查询之前。因此,我认为数据库读取是由UI线程("main"线程)完成的。UI(部分)失去了响应能力这一事实也证实了这一点。如果可能的话,我想做的是在一个单独的线程中运行每个数据库访问,这样,如果有必要的话,可以对查询请求实现Cancel按钮。所以,我想象有这样的工人:

  • UI线程:负责UI;

  • 数据库访问线程:负责从数据库中检索数据;

  • 计划的后台任务:负责其他一切(并使用DB访问线程)。

    这能实现吗?或者,我的方法还有更好的替代方案吗?

附言:我现在不想使用一些现有的框架来解决这个问题(Hibernate、Spring等)。我只需要一个自制的、有效的解决方案。

堆栈跟踪:

    at com.mycompany.myproduct.core.db.SQL.executeQuery(SQL.java:260)
at com.mycompany.myproduct.core.db.Database.getAbstractDBObjects(Database.java:285)
at com.mycompany.myproduct.core.db.Database.getAbstractDBObjects(Database.java:305)
at com.mycompany.myproduct.core.util.job.DummyJobProcessor$1.run(DummyJobProcessor.java:61)
at org.eclipse.swt.widgets.RunnableLock.run(Unknown Source)
at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Unknown Source)
at org.eclipse.swt.widgets.Display.runAsyncMessages(Unknown Source)
at org.eclipse.swt.widgets.Display.readAndDispatch(Unknown Source)
at com.mycompany.myproduct.core.ui.layers.AbstractView.open(AbstractView.java:915)
at com.mycompany.myproduct.mycompany.open(mycompany.java:196)
at com.mycompany.myproduct.mycompany.main(mycompany.java:365)

看起来您的数据库查询是从UI线程运行的,即使您说调度任务运行查询(?)。可以肯定的是,你可以在访问数据库的地方打印出一个堆栈:

new Exception().printStacktrace();

转到您提出的解决方案:如果您的数据库查询很慢,否则会冻结您的UI,那么这似乎是一个不错的设计。您可以在UI层和数据库层之间实现一个事件系统,也许是一种简单的基于队列的方法。

编辑:

以下是最有可能找到如何实现基于事件的解决方案的示例。

免责声明:我已经很多年没有做任何真正的UI编程了。

  1. 用户单击UI中的按钮。UI线程将事件对象(DataWantedEvent)放在队列(java.util.queue)上,更改标签("Waiting for data…"),然后继续等待其他用户交互
  2. 数据库层线程从队列中获取事件并查询数据库。结果将发布回结果对象中的另一个队列
  3. UI线程(可能不是主线程)从结果队列中获取结果对象并更新UI

可能不需要用于将结果对象发布回UI的队列。可以直接调用更新方法。

如果用户单击取消按钮,则可以忽略更新事件/回调,或者,如果可能,可以取消数据库查询。

您可以有一个直接更新UI的监听器实现。类似于函数回调,它向UI线程提供一个事件。

这样,UI线程就可以继续为输入请求提供服务,假设业务逻辑不要求它是同步数据库请求。

您可以始终异步执行。

HTH。

最新更新