上周在柏林的JBoss World上,我介绍了一些高级Hibernate模式。嗯,我本来计划更长时间地谈论我几天前编写的Swing和Hibernate演示应用程序,但结果发现,尽管100%的观众都在使用Hibernate,但只有一位可怜的人需要在两层桌面应用程序场景中与Hibernate打交道。所以我花了更多的时间在其他模式上,并在演示的最后5分钟内仅展示了Swing演示。
我认为更多的人会对这个感兴趣,它经常在论坛和维基百科上出现。必须从Swing应用程序访问数据库而没有中间层的开发者总是有相同的问题:“我如何使用Session?”和“我如何将更新后的对象放入不同的视图?”
这些问题的答案非常相互关联。我并不声称我在演示应用程序中提出的是最佳策略,尽管它作为一个概念验证工作得很好。此外,我是一个糟糕的Swing程序员,只有两个相当小的项目,大约4年前。我实际上当时就在使用Hibernate,但如果我现在看看我的代码,它并不是真的很好。现在要好得多。
首先,这是应用程序的屏幕截图
左边是一个带有树和一个弹出模态对话框的框架,如果您在树中创建或编辑其中一个项目,则会出现该对话框。在右侧是一个带有面板的框架,在该面板中有一个标签和一个表格。这些视图分配给控制器,控制器也处理每个视图的模型。我更喜欢这个层次化的MVC模式,因此您最终会得到MVC三元组
现在,所有这些都独立于持久化上下文(想想Hibernate Session)。我编写了一个非常小的HMVC框架,该框架支持对持久化上下文的任意范围(它始终绑定到当前线程,这也是一个正交的关注点)。持久化上下文的范围取决于我对特定MVC子树的期望。我是否想要在该子树中使用单个身份范围?我是否想要一个特定数据库行的内存表示?如果是这样,那么我使用相同的持久化上下文来处理该子树中的所有控制器。查看下载包中的控制器超类。
如果我不想使用相同的身份作用域,我可以在不同的持久化上下文中传递分离的实例,并在必要时重新附加它们。在演示应用程序中,我可以轻松实现右侧项目列表的视图,使用不同的持久化上下文,并将选定的类别传递给ItemListController。
我还需要在控制器之间传递其他东西,所有类型的事件。例如,如果用户在左侧选择了一个类别,我会触发一个CategorySelectedEvent。任何注册了该事件监听器的控制器都会收到该事件。事件的传播由控制器完成,我可以决定事件是否只向下传播到子控制器,或者全局传播到层次结构树中的每个控制器(一个应用程序可以有多个HMVC树)。我还可以在事件中放入有效负载,例如,将分离的对象传输到不同的持久化上下文。
事务处理也是一个正交的关注点。数据访问可能发生在幕后,例如,当用户展开树节点时。或者,点击按钮并执行操作。当Swing数据模型(这里是一个TreeModel)访问其绑定的实体对象时,无法真正地将事务边界(BEGIN和COMMIT)包裹在按需数据检索周围。因此,这是一个自动提交模式适用于读取的场景。持久化上下文仍然为所有实体实例提供可重读。另一方面,所有在执行操作时显式执行的数据访问(按钮被点击)都包裹在常规事务块中。演示框架也有相应的代码。
您可以在此处下载演示应用程序[1] - 我需要找到一些时间来更好地记录这个(尽管源代码中有些Javadoc)。