如何在Java EE中建模?

时间:2010-04-14 06:33:56

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

让我们说,我决定使用Java EE堆栈来实现我的企业应用程序。

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

例如,

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

  2. 建议您在域模型中积极使用持久性供应商提供的* QL吗?我不知道由于大量使用类似HQL的语言而产生的任何现实问题(如性能,可伸缩性,可移植性等)。 为什么我这样问:我希望尽可能避免编写自定义代码,而这些代码可以通过比SQL更便携的查询语言来完成。

  3. 抱歉,我是这个地区的新手。我在哪里可以找到关于这个主题的更多信息?

2 个答案:

答案 0 :(得分:8)

以下是我认为的传统观点:

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

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

如果将其映射到Java EE技术,通常会得到类似的结果:

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

这是一个粗略的草图,有很多可能的变种。您可以特别跳过会话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,更具体地说是图案{{3} },Data Access ObjectRepository pattern(如果是网络应用),也许Open Session in View

编辑2

好的,还有一些关于交易的句子:

交易应在概念上在业务层进行管理;在一个工作单元中需要做的事情的定义是否一致取决于应用程序的逻辑。

使用EJB3,可以使用注释和应用程序声明事务。服务器为您管理。有关详细信息,请参阅我的Anemic Domain Model。使用Spring,您还可以声明性地标记事务,但我不知道详细信息。否则,您需要自己开始/停止交易。无论您使用JDBC事务还是JTA事务,这都会略有不同。

事务还涉及Hibernate / JPA中的延迟加载。延迟加载的实体只有在存在当前事务时才能加载。如果事务在业务层中终止,则需要急切地加载返回到表示层的实体。

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

答案 1 :(得分:4)

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

我个人害怕因为你问的原因而使用过多的HQL与(N)Hibernate,但有时候它是不可避免的。你已经知道并且自己强调了那里的主要问题,所以你不太可能过度使用它。