让我们说,我决定使用Java EE堆栈来实现我的企业应用程序。
现在,对于域建模(或:用于设计MVC的M),我可以安全地假设和使用哪些API,以及我应该远离... ...通过一层抽象?
例如,
我应该继续使用Hibernate / JPA API调用我的模型吗?或者,我应该构建一个抽象...我自己的持久层,以避免对这两个特定的持久性API进行硬编码? 为什么我这样问: 几年前,有一个Kodo API被Hibernate取代。如果有人设计了一个持久层并对该层编码了模型的其余部分(而不是通过调用特定的供应商API来乱丢模型),那么它就可以(相对)轻松地从Kodo切换到Hibernate到xyz。
是否建议在域模型中积极使用持久性供应商提供的* QL?我不知道由于大量使用类似HQL的语言而产生的任何现实问题(如性能,可伸缩性,可移植性等)。 为什么我这样问: 我希望尽可能避免编写自定义代码,同时可以通过比SQL更便携的查询语言来完成。
对不起,但我是这个地区的新手。我在哪里可以找到关于此主题的更多信息?
以下是我认为的传统观点:
- 项目中的实体构成域模型。它们应该是可重用的,而不是与持久性技术紧密耦合(稍后我会回来讨论紧耦合和松散耦合)
- 业务层使用域模型,但也公开服务和其他东西。
- 数据访问层负责将域模型(实体)持久存储在持久性存储中。
实体不应直接调用数据访问层。但是业务层将以加载和持久化域模型实体的方式进行。
如果将其映射到Java EE技术,通常会得到以下内容:
- 实体 - >带有Hibernate / JPA注释的POJO。请注意,注释并不意味着与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模式 - 重新思考最佳实践,这本书 领域驱动设计 更具体地说是模式 数据访问对象, 存储库模式, 在视图中打开会话 (如果它是一个网络应用程序),也许 贫困领域模型。
编辑2
好的,还有一些关于交易的句子:
交易应在概念上在业务层中进行管理;在一个工作单元中需要做的事情的定义是否一致,取决于应用程序的逻辑。
使用EJB3,可以使用注释和应用程序声明事务。服务器为您管理。看到 这个答案 我的更多信息。使用Spring,您还可以声明性地标记事务,但我不知道详细信息。否则,您需要自己开始/停止交易。无论您使用JDBC事务还是JTA事务,这都会略有不同。
事务还涉及Hibernate / JPA中的延迟加载。延迟加载的实体只有在存在当前事务时才能加载。如果事务在业务层中终止,则需要急切地加载返回到表示层的实体。
为了解决这个问题,Web应用程序的流行模式是 在视图中打开会话,我已经提到过。在这种情况下,表示层启动/停止事务(在概念上略有错误),但在延迟加载时工作得很好。
以下是我认为的传统观点:
- 项目中的实体构成域模型。它们应该是可重用的,而不是与持久性技术紧密耦合(稍后我会回来讨论紧耦合和松散耦合)
- 业务层使用域模型,但也公开服务和其他东西。
- 数据访问层负责将域模型(实体)持久存储在持久性存储中。
实体不应直接调用数据访问层。但是业务层将以加载和持久化域模型实体的方式进行。
如果将其映射到Java EE技术,通常会得到以下内容:
- 实体 - >带有Hibernate / JPA注释的POJO。请注意,注释并不意味着与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模式 - 重新思考最佳实践,这本书 领域驱动设计 更具体地说是模式 数据访问对象, 存储库模式, 在视图中打开会话 (如果它是一个网络应用程序),也许 贫困领域模型。
编辑2
好的,还有一些关于交易的句子:
交易应在概念上在业务层中进行管理;在一个工作单元中需要做的事情的定义是否一致,取决于应用程序的逻辑。
使用EJB3,可以使用注释和应用程序声明事务。服务器为您管理。看到 这个答案 我的更多信息。使用Spring,您还可以声明性地标记事务,但我不知道详细信息。否则,您需要自己开始/停止交易。无论您使用JDBC事务还是JTA事务,这都会略有不同。
事务还涉及Hibernate / JPA中的延迟加载。延迟加载的实体只有在存在当前事务时才能加载。如果事务在业务层中终止,则需要急切地加载返回到表示层的实体。
为了解决这个问题,Web应用程序的流行模式是 在视图中打开会话,我已经提到过。在这种情况下,表示层启动/停止事务(在概念上略有错误),但在延迟加载时工作得很好。
您的域模型及其持久层理论上应该是分开的 - 不需要调用的类 Entity
要知道是否以及如何持久化,所以你可以使用像Hibernate这样的东西来创建持久层而不会污染域模型类本身。您没有“针对该层对[...]模型进行编码” - 您对模型进行编码,然后将其映射到具有某种ORM层的持久性存储,其中域模型不依赖于ORM层。显然,持久层将取决于域模型,但这很好。
因为你问的原因,我个人害怕使用(N)Hibernate过多的HQL,但有时候它是不可避免的。你已经知道并且自己强调了那里的主要问题,所以你不可能过度使用它。