【问题标题】:Java Desktop-App design - MVC with HibernateJava 桌面应用程序设计 - 带有 Hibernate 的 MVC
【发布时间】:2013-09-28 06:25:50
【问题描述】:

我有一些关于我的 Java 应用程序的设计问题。 该软件是一个桌面应用程序,它使用 MySQL 数据库来存储不同类型的对象(客户、员工、文档)。每个员工都有一个客户集合,每个客户都包含许多文档。整个结构是通过休眠延迟加载的。

我目前使用这四个层来构建我的应用程序

  • model - 包含数据的对象,例如客户、员工……
  • 视图 - 每个操作的视图(添加客户、创建文档……)
  • 控制器 - 每个视图都有自己的控制器,用于控制一个或多个业务对象
  • 业务对象 - 封装模型上的操作逻辑(添加客户 = customerBO,添加文档 = documentBO,...)

因此,当用户现在想要向客户添加新文档时,客户视图的控制器会打开一个新的——我们称之为——“文档窗口”,它有自己的控制器。 由于每个文档都必须属于客户,因此我将客户作为参数传递。但是如果我使用这种方式,我必须确保当前休眠会话已打开,并且客户对象重新附加到会话以使用延迟加载。

所以我现在的问题是:有没有更优雅的方法来做到这一点?也许通过存储当前活跃客户的会话类?还是我的总体结构中存在我没有看到的错误?

【问题讨论】:

    标签: java hibernate oop


    【解决方案1】:

    这对于数据传输对象或值对象可能是一个很好的用途。简而言之,在您的 UI 代码中为客户使用只读、非休眠、分离的表示,而不是 Hibernate 创建的表示。此客户对象将是您的 UI 需要的后端完整客户对象的最小投影。实际上,您可能只需要一个名称和 ID(当然取决于您的 UI)。

    过去,我引入了一个“服务”接口,该接口仅适用于这些值对象或 DTO(这些术语真正不能互换,但我正在尝试要灵活,重要的是概念:-))。

    当保存代表客户完成的某些事情时,调用服务组件service#attachDocument(customer.getCustomerId()) 或其他。该组件将与 Hibernate 交互以检索客户并调用 customer.addDocument(documentId)(或适合您的模型的任何内容)。

    【讨论】:

      【解决方案2】:

      首先,做这样的事情并不少见:

      DocumentService {
         public Document addDocument(int customerId) {
               Customer customer = session.getById(Customer.class, customerId);
               Document document = new Document();
               customer.getDocuments().add(document);
               session.update(customer);
               return document;
         }
      }
      

      因此,最终在添加文档之前读取客户可能看起来像是一种性能损失,但如果您不想传递完整的客户对象,那么这是可行的方法。

      通常我使用像 CustomerInfo 对象这样的东西,它只存储一些相关信息,如 id、名称、可能是地址等。通常不经常更改的所有内容,如果用户看到陈旧的数据,则并不重要。 (如果很关键,通常使用通知事件/消息来更新相关信息对象)。

      现在您可以将这些 CustomerInfo 传递给许多常见的服务方法。如果从数据库加载客户对象,我通常会更新客户信息对象以尽可能保持同步。

      这里只有一个规则。由于客户信息可能包含陈旧的数据(其他用户已更改它,您需要验证其有效性。您可以向其引入 @Version 或比较相关属性(如果它们已经更改)。(您使用乐观日志,又名 long用户事务和两个或多个短数据库事务)。

      所以最后使用 reattach 是没有错的。

      如果您有一个本地嵌入式数据库,并且使用 hibernate 的应用程序是唯一的用户(单用户设置),您可能需要考虑使用单会话方法,在该方法中同步或汇集对会话的每次访问以避免并发事务 /访问数据库。

      这样可以确保只有一个对象代表每个“数据库对象/行”。这使得假设每个对象和每个 Info 都与数据库同步变得很容易。只有在会话丢失的情况下,您必须通过将应用程序使用的所有实体重新附加到新会话来进行恢复,以避免出现两个实体对象代表同一数据库行的情况,这在休眠中是不允许的。

      总结

      • 使用附加没有错。
      • 在应用程序中传递实体实例并没有错。
      • 记住:Hibernate 通常发出一个选择来刷新对象并验证它代表当前会话/事务看到的当前数据库状态(使用@Version 来降低成本)。
      • 您可以使用 CustomerInfo / DocumentInfo 对象来避免传递实体实例以减少内存占用并避免重新加载。
      • 如果性能是一个问题,您可以直接使用 id 创建文档,然后使用您从插入 (SQL) 语句中选择的 id 创建 DocumentInfo。这样您就不必重新加载用户或创建文档对象。这只是为了减少内存占用并提高性能,但接缝不是您的问题。

      我的建议,只要您没有内存消耗问题,请坚持重新附加。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-09
        • 2017-11-29
        • 1970-01-01
        • 2011-07-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多