如何在 Java EE 中建模?
比方说,我决定为我的企业应用程序使用 Java EE 堆栈。
现在,对于领域建模(或者:为了设计 MVC 的 M),我可以安全地假设和使用哪些 API,以及我应该远离哪些 API……比如说,通过抽象层?
例如,
我应该继续在我的模型中调用 Hibernate/JPA API 吗?或者,我应该构建一个抽象……一个我自己的持久层,以避免针对这两个特定的持久 API 进行硬编码? 为什么我问这个:几年前,有一个 Kodo API 被 Hibernate 取代。如果设计了一个持久层并针对该层编写了模型的其余部分(而不是通过调用特定供应商 API 来乱七八糟地调用模型),那么就可以(相对)轻松地从 Kodo 切换到 Hibernate 再到 xyz。< /p>
是否建议在域模型中积极使用持久性供应商提供的 *QL?我不知道大量使用类似 HQL 的语言会产生任何现实问题(例如性能、可扩展性、可移植性等)。 为什么我问这个:我想尽可能避免编写自定义代码,因为同样可以通过比 SQL 更可移植的查询语言来完成。
抱歉,但我是这个领域的新手。我在哪里可以找到有关此主题的更多信息?
Let's say, I have decided to go with Java EE stack for my enterprise application.
Now, for domain modelling (or: for designing the M of MVC), which APIs can I safely assume and use, and which I should stay away from... say, via a layer of abstraction?
For example,
Should I go ahead and litter my Model with calls to Hibernate/JPA API? Or, should I build an abstraction... a persistence layer of my own to avoid hard-coding against these two specific persistence APIs? Why I ask this: Few years ago, there was this Kodo API which got superseded by Hibernate. If one had designed a persistence layer and coded the rest of the model against this layer (instead of littering the Model with calls to specific vendor API), it would have allowed one to (relatively) easily switch from Kodo to Hibernate to xyz.
Is it recommended to make aggressive use of the *QL provided by your persistence vendor in your domain model? I'm not aware of any real-world issues (like performance, scalability, portability, etc) arising out of a heavy use of an HQL-like language. Why I ask this: I would like to avoid, as much as possible, writing custom code when the same could be accomplished via query language that is more portable than SQL.
Sorry, but I'm a complete newbie to this area. Where could I find more info on this topic?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
理论上,您的域模型及其持久层应该是分开的 - 不需要名为 Entity 的类知道它是否以及如何持久化,因此您可以使用 Hibernate 之类的东西来创建持久性层而不污染域模型类本身。您不需要“针对该层对模型进行编码” - 您对模型进行编码,然后将其映射到具有某种 ORM 层的持久存储,其中域模型不依赖于 ORM 层。显然,持久层将取决于域模型,但这没关系。
出于你所问的原因,我个人不愿意在 (N)Hibernate 中使用过多的 HQL,但有时这是不可避免的。您已经知道并强调了其中的主要问题,因此无论如何您都不可能过度使用它。
Your domain model and its persistence layer should in theory be separate - there's no need for a class called
Entity
to know anything about if and how it is persisted, so you could use something like Hibernate to create the persistence layer without polluting the domain model classes themselves. You don't "code the [...] model against this layer" - you code the model, then map it to a persistent store with some sort of ORM layer, where the domain model does not depend on the ORM layer. Obviously the persistence layer will depend on the domain model, but that's fine.I personally fight shy of using too much HQL with (N)Hibernate for the reason you ask, but there are times where it is unavoidable. You already know, and have yourself highlighted, the main issue there, so you are unlikely to overuse this anyway.
我认为这是传统的观点:
实体不应直接调用数据访问层。但业务层将以某种方式加载和持久化域模型的实体。
如果将其映射到 Java EE 技术,您通常会得到类似以下内容:
这是一个粗略的草图,有很多可能的变体。您可以特别跳过会话 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 模式 - 重新思考最佳实践一书,领域驱动设计,更具体地说是模式数据访问对象,存储库模式< /a>、在视图中打开会话(如果用于 Web 应用程序),也许 < a href="http://martinfowler.com/bliki/AnemicDomainModel.html" rel="nofollow noreferrer">贫血域模型。
EDIT 2
好吧,再多说几句关于事务的事情:从
概念上讲,事务应该在业务层进行管理;一个工作单元中需要完成哪些工作才能保持一致的定义实际上取决于应用程序的逻辑。
使用 EJB3,可以使用注释和应用程序来声明事务。服务器为您管理。请参阅我的这个其他答案了解更多信息。使用 Spring,您还可以以声明方式标记事务,但我不知道详细信息。否则,您将需要自己启动/停止交易。无论您使用 JDBC 事务还是 JTA 事务,这都会略有不同。
事务还与 Hibernate/JPA 中的延迟加载相关。延迟加载的实体实际上只有在存在当前事务时才能加载。如果事务在业务层终止,则需要立即加载返回到表示层的实体。
为了规避这个问题,Web 应用程序的一种流行模式是 在视图中打开会话,我已经这样做了提及。在这种情况下,表示层启动/停止事务(这在概念上略有错误),但在延迟加载时工作得很好。
Here is what I believe is the traditional view:
An entity should not call the data access layer directly. But the business layer will, in a way to load and persist entities of the domain model.
If you map that to Java EE technologies you usually get something like:
That's a rough sketch and there are a lot of possible variants. You can notably skip the session EJB and implement the business layer another way. You can also decide to have the business layer call the JPA/Hibernate Session/EntityManager directly, in which case JPA/Hibernate is really the DAL, or you may want to wrap access the Session/EntityManager into so-called Data Access Objects (DAO).
Regarding HQL, try to stick to what's portable, and if you use native SQL, follow SQL-92 conventions. If stuffs get complicated, maybe introduce DAOs. This way, you know that the only place where there are HQL queries is in the DAOs. You can also first implement the query logic "procedurally" in the DAO, and if you have performance problem, re-implement it with a more complicated HQL query.
EDIT
Regarding your questions in the comment:
The business layer depends on the data layer. If you want the business layer to not depend on Hibernate/JPA then your data layer need to abstract Hibernate/JPA away. If you use DAO for your data layer, that will be the case. The DAO will be the "thin hand-written persistence layer over Hibernate" (to take your words). I would introduce DAO for all entities in your case.
What your are asking is a pretty generic design question. I can not give a definitive recipe for that, nor possibly summarize all variants in one answer as it depends on case by case. For instance, we didn't spoke so far about the problem of transactions, that you usually start in the business layer, but that the data layer must be aware of. This typically depends on the technologies used and your requirements.
Still, here is a list of resources that you might be interested in: the books Pattern of Enterprise Application Architecture, the book Real World Java EE Patterns - Rethinking Best Practices, the book Domain Driven Design and more specifically the patterns Data Access Object, Repository pattern, Open Session in View (if it's for a web app), and maybe Anemic Domain Model.
EDIT 2
Ok, a few more sentences about transactions:
Transactions should conceptually be managed in the business layer; the definition of what needs to be done in one unit of work to be consistent depends indeed on the very logic of the application.
With EJB3, transactions can be declared with annotations and the app. server manages that for you. See this other answer of mine for more information. With Spring you can also mark the transactions declaratively, but I don't know the details. Otherwise you will need to start/stop the transaction yourself. This will be slightly different whether you use JDBC transactions or JTA transactions.
Transactions also relates to lazy loading in Hibernate/JPA. An entity that was lazy loaded, can indeed be loaded only if there is a current transaction. If the transactions is terminated in the business layer, entities that are returned to the presentation layer need to be eagerly loaded.
To circumvent this problem, a popular pattern for web applications is Open Session in View, which I already mentioned. In this case, the presentation layer start/stop the transactions (which is slightly wrong conceptually), but works just fine with lazy loading.