在视图模式中打开会话

2022-09-04 06:58:57

我问这个问题,因为我选择了JPA(Hibernate实现),Spring和<在这里插入MVC框架的开发框架 - Struts 1,Struts 2,Spring MVC,Stripes...>.

我一直在思考实体层中的关系 - 例如,我有一个订单实体,它有很多订单行。我已经设置了我的应用程序,以便它热切地加载每个订单的订单行。您是否认为这是一种解决懒惰初始化问题的懒惰方法,如果我将获取策略设置为false,我会遇到这些问题?

在我看来,在检索实体及其关联时,我具有以下替代方法:

  1. 使用“在视图中打开会话”模式在每个请求上创建会话,并在返回响应之前提交事务。

  2. 实现一个 DTO(数据传输对象)层,以便我执行的每个 DAO 查询都返回正确初始化的 DTO 以实现我的目的。我不太喜欢这个选项,因为根据我的经验,我发现它创建了很多样板复制代码,并且维护起来很混乱。

  3. 不要在JPA中映射任何关联,以便我执行的每个查询只返回我感兴趣的实体 - 这可能无论如何都需要我拥有DTO,并且维护起来会很痛苦,我认为首先违背了拥有ORM的目的。

  4. 急切地获取所有(或大多数关联) - 在上面的示例中,当我检索订单时,始终获取所有订单行。

所以我的问题是,你什么时候以及在什么情况下会使用这些选项中的哪一个?你总是坚持一种方法吗?

我会问一位同事,但我认为,如果我提到“公开会议”这个词,我会被茫然的目光所吸引:(我在这里真正想要的是来自资深或非常有经验的开发人员的一些建议。

谢谢你们!


答案 1

在视图中打开会话存在一些问题

例如,如果事务失败,您可能在提交时知道它太晚了,一旦您即将完成呈现页面(可能是响应已经提交,因此您无法更改页面!) ...如果您以前知道该错误,那么您将遵循不同的流程并最终呈现不同的页面...

另一个例子,按需读取数据可能会变成许多“N + 1选择”问题,从而扼杀您的性能。


许多项目使用以下路径:

  1. 在业务层维护交易;此时加载您应该需要的所有内容。
  2. 表示层存在LazyExceptions的风险:每个都被认为是编程错误,在测试期间捕获,并通过在业务层中加载更多数据来纠正(您有机会有效地做到这一点,避免“N + 1选择”问题)。

若要避免为 DTO 创建额外的类,可以在实体对象本身内加载数据。这就是POJO方法的全部意义(现代数据访问层,甚至像Spring这样的集成技术)。


答案 2

我已经成功地解决了我所有的懒惰初始化问题,使用Open Session In View -pattern(即Spring实现)。我使用的技术与你完全相同。

使用此模式,我可以完全映射实体关系,而不必担心在 dao 中获取子实体。主要。在 90% 的情况下,模式解决了视图中的延迟初始化需求。在某些情况下,您必须“手动”初始化关系。这些情况很少见,在我的案例中总是涉及非常非常复杂的映射。

使用开放式实体管理器视图模式时,正确定义实体关系,尤其是传播和事务设置非常重要。如果未正确配置这些,则当某些实体在视图中延迟初始化并且由于会话已关闭而失败时,将会出现与已关闭会话相关的错误。

我肯定会选择1。有时可能需要选项2,但我认为绝对没有理由使用选项3。选项4也是一个不行。急切地获取所有内容会扼杀任何只需要列出某些父实体的几个属性(tis 中的订单)的视图的性能。

N+1 选择

在开发过程中,由于初始化视图中的某些关系,将有 N+1 个选择。但这并不是放弃模式的理由。只需在出现这些问题时以及在将代码交付到生产环境之前修复它们即可。使用OEMIV模式修复这些问题与使用任何其他模式一样容易:添加适当的dao或服务方法,修复控制器以调用不同的查找器方法,可能向数据库添加视图等。


推荐