在视图模式中打开会话

JMM*_*JMM 13 java orm session design-patterns

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

我一直在考虑我的实体层中的关系 - 例如我有一个订单实体,它有许多订单行.我已经设置了我的应用程序,因此它急切地为每个订单加载订单行.如果我将获取策略设置为false,你认为这是一种解决我会遇到的延迟初始化问题的懒惰方法吗?

我看到它的方式,在检索实体及其关联时,我有以下备选方案:

  1. 使用Open Session In View模式在每个请求上创建会话,并在返回响应之前提交事务.

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

  3. 不要在JPA中映射任何关联,以便我执行的每个查询都只返回我感兴趣的实体 - 这可能要求我无论如何都要有DTO,这将是一个难以维护的问题,我认为这样做会破坏ORM的目的首先.

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

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

我会问一位同事,但我认为,如果我甚至提到"开放式会议"这一术语,我会受到空白的盯着:(我真正想要的是来自资深或经验丰富的开发人员的一些建议.

多谢你们!

KLE*_*KLE 15

Open View in View存在一些问题.

例如,如果事务失败,您可能在提交时知道得太晚,一旦您几乎完成渲染页面(可能已经提交了响应,因此您无法更改页面!)...如果您已经知道之前的那个错误,你会遵循不同的流程并最终呈现一个不同的页面......

其他例子,按需读取数据可能会转向许多"N + 1选择"问题,这会影响您的性能.


许多项目使用以下路径:

  1. 维护业务层的交易 ; 在那一点加载你应该需要的一切.
  2. 表示层冒着LazyExceptions的风险:每个都被认为是编程错误,在测试期间被捕获,并通过在业务层中加载更多数据来纠正(您有机会有效地执行此操作,避免"N + 1选择"问题).

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

  • @kosoant我理解你的观点,并认为你在某些条件下是正确的.但是直接调用DAO而不涉及业务层有一些缺点.在我们的项目和许多其他大项目中,业务层还有其他不能绕过的职责(安全,日志记录等)...... (3认同)

kos*_*ant 10

我已经成功解决了Open Session In View -pattern(即Spring实现)的所有延迟初始化问题.我使用的技术与您完全相同.

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

在视图模式中使用Open Entity Manager时,正确定义实体关系,尤其是传播和事务设置非常重要.如果这些配置不正确,当某个实体在视图中被懒惰地初始化并且由于会话已经关闭而失败时,将会出现与已关闭会话相关的错误.

我肯定会选择选项1.有时可能需要选项2,但我认为绝对没有理由使用选项3.选项4也是不可以.急切地获取所有内容会导致任何需要列出某些父实体的几个属性的视图的性能(在这种情况下为订单).

N + 1选择

在开发期间,由于初始化视图中的某些关系,将会有N + 1个选择.但这并不是放弃这种模式的理由.只需解决这些问题,并在将代码交付到生产环境之前.使用OEMIV模式解决这些问题就像使用任何其他模式一样容易:添加正确的dao或服务方法,修复控制器以调用不同的finder方法,可能会向数据库添加视图等.