如何在Java EE中建模?

Har*_*rry 11 modeling java-ee data-persistence java-ee-6

比方说,我决定使用Java EE堆栈来实现我的企业应用程序.

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

例如,

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

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

对不起,我是这个地区的新手.我在哪里可以找到关于此主题的更多信息?

ewe*_*nli 8

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

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

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

如果将其映射到Java EE技术,通常会得到以下内容:

  • 实体 - > POJO与Hibernate/JPA注释.请注意,注释并不意味着与JPA/Hibernate紧密耦合,在没有Hibernate的情况下,可以在其他地方使用相同的POJO.
  • 业务层 - >会话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.

你问的是一个非常通用的设计问题.我不能给出明确的方法,也不可能在一个答案中总结所有变体,因为它取决于具体情况.例如,到目前为止,我们没有谈到交易问题,您通常从业务层开始,但数据层必须知道.这通常取决于所使用的技术和您的要求.

不过,这里要说的是,你可能会感兴趣的资源列表:书籍企业应用架构模式,这本书真实世界的Java EE模式-反思最佳实践,这本书领域驱动设计和更具体的模式数据访问对象,资源库模式,在视图中打开会话(如果它是用于Web应用程序),也可能是Anemic Domain Model.

编辑2

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

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

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

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

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

  • 我完全同意,并最终建议使用JPQL而不是HQL来坚持标准. (2认同)