【问题标题】:How to model in Java EE?如何在 Java EE 中建模?
【发布时间】:2010-04-14 06:33:55
【问题描述】:

假设,我决定为我的企业应用程序使用 Java EE 堆栈。

现在,对于域建模(或:用于设计 MVC 的 M),我可以安全地假设和使用哪些 API,以及我应该远离哪些……比如说,通过抽象层?

例如,

  1. 我应该继续调用 Hibernate/JPA API 来乱扔我的模型吗?或者,我应该构建一个抽象......一个我自己的持久层以避免对这两个特定的持久性 API 进行硬编码? 我为什么要问这个:几年前,这个 Kodo API 被 Hibernate 取代了。如果设计了一个持久层并针对该层对模型的其余部分进行编码(而不是通过调用特定的供应商 API 来乱扔模型),它将允许一个人(相对)轻松地从 Kodo 切换到 Hibernate 再到 xyz。

  2. 是否建议在域模型中积极使用持久性供应商提供的 *QL?我不知道由于大量使用类似 HQL 的语言而引起的任何实际问题(如性能、可伸缩性、可移植性等)。 问这个问题的原因:我想尽可能避免编写自定义代码,因为这可以通过比 SQL 更可移植的查询语言来完成。

抱歉,我完全是这个领域的新手。在哪里可以找到有关此主题的更多信息?

【问题讨论】:

    标签: jakarta-ee java-ee-6 modeling data-persistence


    【解决方案1】:

    这是我认为的传统观点:

    • 项目中的实体构成域模型。它们应该是可重用的,而不是与持久性技术紧密耦合(稍后我将讨论紧耦合与松耦合)
    • 业务层,使用领域模型,但也暴露服务和其他东西。
    • 数据访问层负责将域模型(实体)持久存储在持久存储中。

    实体不应直接调用数据访问层。但业务层将以某种方式加载和持久化领域模型的实体。

    如果您将其映射到 Java EE 技术,您通常会得到如下信息:

    • 实体 --> 带有 Hibernate/JPA 注释的 POJO。请注意,注释并不意味着与 JPA/Hibernate 紧密耦合,相同的 POJO 可以在没有 Hibernate 的其他地方使用。
    • 业务层 --> Session EJB 或 Spring
    • 数据访问层 --> JPA/Hibernate

    这是一个粗略的草图,有很多可能的变体。您可以明显地跳过会话 EJB 并以另一种方式实现业务层。您还可以决定让业务层直接调用 JPA/Hibernate Session/EntityManager,在这种情况下 JPA/Hibernate 确实是 DAL,或者您可能希望将 Session/EntityManager 的访问包装到所谓的数据访问对象(DAO )。

    关于 HQL,尽量坚持什么是可移植的,如果您使用原生 SQL,请遵循 SQL-92 约定。如果事情变得复杂,也许可以引入 DAO。这样,您就知道唯一存在 HQL 查询的地方就是 DAO。你也可以先在DAO中“程序化”实现查询逻辑,如果遇到性能问题,再用更复杂的HQL查询重新实现。

    编辑

    关于你在评论中的问题:

    业务层依赖于数据层。如果您希望业务层不依赖于 Hibernate/JPA,那么您的数据层需要抽象 Hibernate/JPA。如果您将 DAO 用于数据层,情况就是如此。 DAO 将是“Hibernate 上的薄手写持久层”(用你的话来说)。在您的案例中,我将为所有实体介绍 DAO。

    您要问的是一个非常通用的设计问题。我无法为此给出明确的配方,也无法在一个答案中总结所有变体,因为这取决于具体情况。例如,到目前为止,我们还没有谈到事务问题,您通常从业务层开始,但数据层必须意识到这一点。这通常取决于所使用的技术和您的要求。

    不过,这里是您可能感兴趣的资源列表:书籍Pattern of Enterprise Application Architecture、书籍Real World Java EE Patterns - Rethinking Best Practices、书籍Domain Driven Design,更具体地说是模式Data Access ObjectRepository pattern、@987654326 @(如果是用于 Web 应用程序),也许是 Anemic Domain Model

    编辑 2

    好吧,再说几句关于交易的:

    事务在概念上应该在业务层进行管理;一个工作单元中需要做什么才能保持一致的定义确实取决于应用程序的逻辑。

    使用 EJB3,可以使用注释和应用程序声明事务。服务器为您管理。有关更多信息,请参阅我的this other answer。使用 Spring,您还可以以声明方式标记事务,但我不知道细节。否则,您将需要自己启动/停止交易。无论您使用 JDBC 事务还是 JTA 事务,这都会略有不同。

    事务还与 Hibernate/JPA 中的延迟加载有关。延迟加载的实体确实只有在存在当前事务时才能加载。如果事务在业务层中终止,则返回到表示层的实体需要预先加载。

    为了规避这个问题,Web 应用程序的一个流行模式是Open Session in View,我已经提到过。在这种情况下,表示层启动/停止事务(这在概念上有点错误),但在延迟加载时工作得很好。

    【讨论】:

    • 我完全同意,并且最终会推荐使用 JPQL 而不是 HQL 以坚持标准。
    • 我在这里的术语可能是错误的。当我说“领域建模”时,我指的是 MVC 三元组的 M,本质上是“核心应用程序”(包括业务层),您甚至可以通过命令行界面驱动它(通过重写 V和 CLI 的 C)!现在,这个 M 要做的事情之一就是坚持。为此,M 需要没有任何和所有供应商特定的持久性内容。因此,在 Hibernate 上需要一个薄的(或厚的/复杂的?)手写持久层。如果我在这里错了,请您纠正我。
    • "如果事情变得复杂,也许可以引入 DAO。"您的意思是,根据具体情况(当然,假设 DAO 和 HQL/JPQL 和平共存)。我真的希望能够以这样一种方式设计我的对象,即 HQL 在大多数情况下就足够了(由于关系范式的力量),对于真正复杂的查询,我编写命令式代码。
    • “这是一个粗略的草图,有很多可能的变体。”我在哪里可以找到有关这些变体的更多信息以及支持理由?
    • "例如,到目前为止,我们还没有谈到事务的问题,您通常从业务层开始,但数据层必须意识到这一点。这通常取决于技术使用和您的要求。”在我将此线程标记为已关闭之前,请您/请/就这个交易主题多说几句。如果您提到的书籍/模式中涵盖了该主题,请您说明一下……因为我对首先了解这件事感到非常不安,而不是其他任何事情。顺便说一句,到目前为止,即使您决定不回复(无论出于何种原因)。
    【解决方案2】:

    理论上你的域模型和它的持久层应该是分开的 - 不需要一个名为 Entity 的类来知道它是否以及如何持久化,所以你可以使用 Hibernate 之类的东西来创建持久层,而无需污染领域模型类本身。您不会“针对该层对 [...] 模型进行编码” - 您对模型进行编码,然后将其映射到具有某种 ORM 层的持久存储,其中域模型不依赖于 ORM 层。显然持久层将依赖于领域模型,但这很好。

    出于您所问的原因,我个人避免在 (N)Hibernate 中使用过多的 HQL,但有时这是不可避免的。您已经知道并强调了那里的主要问题,因此无论如何您都不太可能过度使用它。

    【讨论】:

    • "然后将其映射到具有某种 ORM 层的持久存储":是的,我只是这个意思。看来您的意思是:在 Hibernate 之上构建一个层,而不是乱扔直接调用 Hibernate API 调用的模型,对吧?
    • 关闭但不完全,我是说建立一个模型,然后将其连接到持久层。当您编写域模型类时,您并不关心它们是如何进入数据库的,也不关心它们是否进入数据库。你当然不应该觉得你是在“在 Hibernate 之上”构建这些类。
    猜你喜欢
    • 2019-05-23
    • 2022-01-14
    • 1970-01-01
    • 1970-01-01
    • 2012-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多