java 在视图模式中打开会话
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1847040/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Open Session In View Pattern
提问by JMM
I'm asking this question given my chosen development frameworks of JPA (Hibernate implementation of), Spring, and <insert MVC framework here - Struts 1, Struts 2, Spring MVC, Stripes...>.
鉴于我选择的 JPA(Hibernate implementation of)、Spring 和 <在此处插入 MVC 框架 - Struts 1、Struts 2、Spring MVC、Stripes...> 的开发框架,我问了这个问题。
I've been thinking a bit about relationships in my entity layer - for example I have an order entity that has many order lines. I've set up my app so that it eagerly loads the order lines for every order. Do you think this is a lazy way to get around the lazy initialization problems that I would come across if I was to set the fetch strategy to false?
我一直在思考我的实体层中的关系 - 例如我有一个订单实体,它有很多订单行。我已经设置了我的应用程序,以便它急切地加载每个订单的订单行。如果我将 fetch 策略设置为 false,您是否认为这是一种解决惰性初始化问题的惰性方法?
The way I see it, I have the following alternatives when retrieving entities and their associations:
在我看来,在检索实体及其关联时,我有以下选择:
Use the Open Session In View pattern to create the session on each request and commit the transaction before returning the response.
Implement a DTO (Data Transfer Object) layer such that every DAO query I execute returns the correctly initialized DTO for my purposes. I don't really like this option much because in my experience I've found that it creates a lot of boilerplate copying code and becomes messy to maintain.
Don't map any associations in JPA so that every query I execute returns only the entities I'm interested in - this will probably require me to have DTOs anyway and will be a pain to maintain and I think defeats the purpose of having an ORM in the first place.
Eagerly fetch all (or most associations) - in the example above, always fetch all order lines when I retrieve an order.
使用 Open Session In View 模式在每个请求上创建会话并在返回响应之前提交事务。
实现一个 DTO(数据传输对象)层,这样我执行的每个 DAO 查询都会为我的目的返回正确初始化的 DTO。我不太喜欢这个选项,因为根据我的经验,我发现它会创建大量样板复制代码,并且维护起来很麻烦。
不要在 JPA 中映射任何关联,以便我执行的每个查询只返回我感兴趣的实体 - 这可能需要我拥有 DTO 并且维护起来会很痛苦,我认为失去了拥有 ORM 的目的首先。
急切地获取所有(或大多数关联) - 在上面的示例中,当我检索订单时,总是获取所有订单行。
So my question is, when and under what circumstances would you use which of these options? Do you always stick with one way of doing it?
所以我的问题是,你会在什么时候以及在什么情况下使用这些选项中的哪一个?你总是坚持一种方法吗?
I would ask a colleague but I think that if I even mentioned the term 'Open Session in View' I would be greeted with blank stares :( What I'm really looking for here is some advice from a senior or very experienced developer.
我会问一位同事,但我认为如果我什至提到“Open Session in View”这个词,我都会用茫然的目光打招呼:(我在这里真正想要的是来自资深或非常有经验的开发人员的一些建议。
Thanks guys!
多谢你们!
采纳答案by kosoant
I've successfully solved all my lazy initialization problems with Open Session In View -pattern (ie. the Spring implementation). The technologies I used were the exact same as you have.
我已经使用 Open Session In View -pattern(即 Spring 实现)成功地解决了我所有的延迟初始化问题。我使用的技术与您使用的完全相同。
Using this pattern allows me to fully map the entity relationships and not worry about fetching child entities in the dao. Mostly. In 90% of the cases the pattern solves the lazy initialization needs in the view. In some cases you'll have to "manually" initialize relationships. These cases were rare and always involved very very complex mappings in my case.
使用这种模式可以让我完全映射实体关系,而不必担心在 dao 中获取子实体。大多。在 90% 的情况下,该模式解决了视图中的延迟初始化需求。在某些情况下,您必须“手动”初始化关系。这些情况很少见,并且在我的情况下总是涉及非常非常复杂的映射。
When using Open Entity Manager In View pattern it's important to define the entity relationships and especially propagation and transactional settings correctly. If these are not configured properly, there will be errors related to closed sessions when some entity is lazily initialized in the view and it fails due to the session having been closed already.
在视图模式中使用开放实体管理器时,正确定义实体关系,尤其是传播和事务设置非常重要。如果这些没有正确配置,当某些实体在视图中延迟初始化并且由于会话已经关闭而失败时,将会出现与关闭会话相关的错误。
I definately would go with option 1. Option 2 might be needed sometimes, but I see absolutely no reason to use option 3. Option 4 is also a no no. Eagerly fetching everything kills the performance of any view that needs to list just a few properties of some parent entities (orders in tis case).
我肯定会选择选项 1。有时可能需要选项 2,但我认为绝对没有理由使用选项 3。选项 4 也是不可以的。急切地获取所有东西会扼杀任何只需要列出一些父实体(在这种情况下是订单)的几个属性的视图的性能。
N+1 Selects
N+1 选择
During development there will be N+1 selects as a result of initializing some relationships in the view. But this is not a reason to discard the pattern. Just fix these problems as they arise and before delivering the code to production. It's as easy to fix these problems with OEMIV pattern as it's with any other pattern: add the proper dao or service methods, fix the controller to call a different finder method, maybe add a view to the database etc.
在开发过程中,将有 N+1 个选择作为初始化视图中某些关系的结果。但这不是丢弃该模式的理由。只需在这些问题出现时和将代码交付到生产环境之前修复它们。使用 OEMIV 模式解决这些问题与使用任何其他模式一样容易:添加适当的 dao 或服务方法,修复控制器以调用不同的 finder 方法,或者向数据库添加视图等。
回答by KLE
Open Session in View has some problems.
在视图中打开会话有一些问题。
For example, if the transaction fails, you might know it too lateat commit time, once you are nearly done rendering your page (possibly the response already commited, so you can't change the page !) ... If you had know that error before, you would have followed a different flow and ended up rendering a different page...
例如,如果事务失败,您可能在提交时知道它为时已晚,一旦您几乎完成呈现您的页面(可能响应已经提交,因此您无法更改页面!)......如果您知道之前的那个错误,你会遵循不同的流程并最终呈现不同的页面......
Other example, reading data on-demand might turn to many "N+1 select" problems, that kill your performance.
其他示例,按需读取数据可能会导致许多“N+1 选择”问题,这会影响您的性能。
Many projects use the following path:
许多项目使用以下路径:
- Maintain transactions at the business layer; load at that point everything you are supposed to need.
- Presentation layer runs the risk of LazyExceptions : each is considered a programming error, caught during tests, and corrected by loading more data in the business layer(you have the opportunity to do it efficiently, avoiding "N+1 select" problems).
- 在业务层维护事务;在那一点加载你应该需要的一切。
- 表示层存在 LazyExceptions 的风险:每个都被认为是一个编程错误,在测试期间被捕获,并通过在业务层加载更多数据来纠正(您有机会高效地做到这一点,避免“N+1 选择”问题)。
To avoid creating extra classes for DTOs, you can load the data inside the entity objects themselves. This is the whole point of the POJO approach (uses by modern data-access layers, and even integration technologies like Spring).
为避免为 DTO 创建额外的类,您可以在实体对象本身内加载数据。这就是 POJO 方法的重点(由现代数据访问层使用,甚至是 Spring 等集成技术)。
回答by David Kemp
I have successfully used the Open-Session-in-View pattern on a project. However, I recently read in "Spring In Practice" of an interesting potential problem with non-repeatable reads if you manage your transactions at a lower layer while keeping the Hibernate session open in the view layer.
我已经成功地在一个项目中使用了 Open-Session-in-View 模式。但是,我最近在“Spring In Practice”中读到了一个有趣的潜在问题,如果您在较低层管理事务,同时在视图层中保持 Hibernate 会话打开,则不可重复读取。
We managed most of our transactions in the service layer, but kept the hibernate session open in the view layer. This meant that lazy reads in the view were resulting in separate read transactions.
我们在服务层管理大部分事务,但在视图层保持休眠会话打开。这意味着视图中的延迟读取会导致单独的读取事务。
We managed our transactions in our service layer to minimize transaction duration. For instance, some of our service calls resulted in both a database transaction and a web service call to an external service. We did not want our transaction to be open while waiting for a web service call to respond.
我们在我们的服务层管理我们的交易以最小化交易持续时间。例如,我们的一些服务调用会导致数据库事务和对外部服务的 Web 服务调用。我们不希望我们的事务在等待 Web 服务调用响应时打开。
As our system never went into production, I am not sure if there were any real problems with it, but I suspect that there was the potential for the view to attempt to lazily load an object that has been deleted by someone else.
由于我们的系统从未投入生产,我不确定它是否有任何真正的问题,但我怀疑视图有可能尝试延迟加载已被其他人删除的对象。
回答by lucas
I'll also throw my weight behind the Open-Session-in-View pattern, having been in the exact same boat before.
我也将把我的重心放在 Open-Session-in-View 模式背后,因为我之前一直在同一条船上。
I work with Stripes without spring, and have created a manual filter before that tends to work well. Coding transaction logic on the backend turns messy really quick as you've mentioned. Eagerly fetching everything becomes TERRIBLE as you map more and more objects to each other.
我在没有弹簧的情况下使用条纹,并且在此之前创建了一个手动过滤器,这往往效果很好。正如您所提到的,后端的编码事务逻辑很快就会变得混乱。当您将越来越多的对象相互映射时,急切地获取所有内容变得非常糟糕。
One thing I want to add that you may not have come across is Stripersist and Stripernate - Stripersist being the more JPA flavor - auto-hydration filters that take a lot of the work off your shoulders.
我想补充的一件事你可能没有遇到过是 Stripersist 和 Stripernate——Stripersist 是 JPA 的味道——自动补水过滤器,可以减轻你的负担。
With Stripersist you can say things like /appContextRoot/actions/view/3and it will auto-hydrate the JPA Entity on the ActionBean with id of 3 before the event is executed.
使用 Stripersist,您可以这样说/appContextRoot/actions/view/3,它会在执行事件之前自动水合 ActionBean 上 id 为 3 的 JPA 实体。
Stripersist is in the stripes-stuff package on sourceforge. I now use this for all new projects, as it's clean and easily supports multiple datasources if necessary.
Stripersist位于 sourceforge 上的stripes-stuff 包中。我现在将它用于所有新项目,因为它很干净并且在必要时可以轻松支持多个数据源。
回答by Petteri Hietavirta
There are some benefits of DTO approach though. You have to think beforehand what information you need. In some cases this will prevent you from generating n+1 select statements. It helps also to see where to use eager fetching and/or optimized views.
不过,DTO 方法有一些好处。你必须事先考虑你需要什么信息。在某些情况下,这会阻止您生成 n+1 条选择语句。它还有助于查看在何处使用预先获取和/或优化视图。
回答by Fabio Kenji
Does the Order and Order Lines compose a high volume of data? Do they take part in online processes where real-time response is required? If so, you might consider not using eager fetching - it does make a huge diference in performance. If the amount of data is small, there is no problem in eager fetching.
订单和订单行是否包含大量数据?他们是否参与需要实时响应的在线流程?如果是这样,您可能会考虑不使用 Eager fetching - 它确实会对性能产生巨大影响。如果数据量很小,用eager fetch是没有问题的。
About using DTOs, it might be a viable implementation. If your business layer is used internally by your own application (i.e a small web app and its business logic) it'd probably be best to use your own entities in your view with open session in view pattern since it's simpler.
关于使用 DTO,它可能是一个可行的实现。如果您的业务层由您自己的应用程序(即小型 Web 应用程序及其业务逻辑)在内部使用,那么最好在视图模式中使用您自己的实体和视图模式中的打开会话,因为它更简单。
If your entities are used by many applications (i.e a backend application providing a service in your corporation) it'd be interesting to use DTOs since you would not expose your model to your clients. Exposing it could mean you would have a harder time refactoring your model since it could mean breaking contracts with your clients. A DTO would make that easier since you have another layer of abstraction. This can be a bit strange since EJB3 would theorically eliminate the need of DTOs.
如果您的实体被许多应用程序(即在您的公司中提供服务的后端应用程序)使用,那么使用 DTO 会很有趣,因为您不会将您的模型暴露给您的客户。暴露它可能意味着您将更难重构您的模型,因为这可能意味着与您的客户签订合同。DTO 会使这更容易,因为您有另一层抽象。这可能有点奇怪,因为 EJB3 理论上会消除对 DTO 的需要。

