OpenSessionInView反模式

有了如此有争议的标题,我一定会成为热烈评论的对象。 尽管具有挑衅性,但这不是我的目标,但是,我只想在有兴趣思考此问题的人们之间发起一场有教养的辩论。

这篇文章的来历是在Hibernate上具有不同经验水平的开发人员之间的简单讨论。 讨论的主题是急切,延迟加载和臭名昭著的LazyInitializationException。 因为我想现在并不是每个人都在想这个问题,所以让我先开始讨论。

在大多数情况下,您的实体之间是相互联系的:一门课程有学生,一张发票有客户,等等。这些关系可以使您真正走得更远(一个学生学习由老师讲授的课程,然后又由其他老师教课程),而且由于在大多数情况下,您不需要整个对象集群,因此Hibernate允许您将关系定义为渴望的或懒惰的。 渴望的关系确实可以建立关联,而懒惰的关系则由代理代替了Hibernate。 这些代理不会执行任何操作,直到通过调用关联的吸气剂将其激活为止。 这时,代理通过其封装的Hibernate会话查询数据库。

如果后者已经关闭,则将获得LayInitializationException,因为Hibernate尝试查询没有连接的数据库。 但是,有3种解决方案。

当然,最简单的方法是将关系标记为渴望。 Hibernate永远不会使用代理,因此,您永远不会有此异常(至少从此关系而言)。 这本身并不是一个解决方案,因为如果您使用所有关系进行此操作,Hibernate将加载所有关联,最终您将得到一个强大的大对象集群。 这击败了Hibernate的惰性策略,并且使JVM的内存中未使用的对象杂乱无章。 在整个应用程序中使用的关联是渴望标记的一个很好的候选者,但这是一个例外,不是规范。

另一个解决方案是OpenSessionInView“模式”。 在开始解释它之前,让我对整个事情进行布局。好的Web应用程序是分层的,这意味着持久层(最接近数据库的那一层)负责与DB进行交互。 大多数DAO都会在方法开始时打开Hibernate会话(或从当前线程获取它,但这是另一回事),使用它对实体进行CRUD。 并将控制权返回给服务层。 从这一点开始,应该不再与数据库交互。

现在,“模式”告诉我们,如果一个Hibernate代理需要访问表示层中的数据库,那么,没问题,我们应该按需打开会话。 这种方法有3个缺点,恕我直言:

  1. 每个惰性初始化都会为您提供一个查询,这意味着每个实体将需要N + 1个查询,其中N是惰性关联的数量。 如果屏幕上显示表格数据,则读取Hibernate日志是一个很大的提示,表明您不应该这样做
  2. 这完全破坏了分层体系结构,因为您在表示层中不满意DB。 这是一个概念上的弊端,所以我可以接受,但是有一个必然结果
  3. 最后但并非最不重要的一点是,如果在获取会话时发生异常,则该异常将在页面的编写过程中发生:您无法向用户显示干净的错误页面,唯一可以做的就是在正文中写入错误消息

这种方法的另一个变体是使用值对象,并让映射框架(例如Dozer)在服务层中调用代理的getter方法。 这样可以正确处理错误,但查询数量仍然相同。

到目前为止,我发现的最佳的延迟初始化最佳解决方案是Hibernate中的“ join fetch”功能,可从Criteria API( setFetchMode(association, FetchMode.EAGER) )和HQL( JOIN FETCH )中获得。 这意味着您的查询方法将旨在为上层提供完整的对象集群。 这也意味着并且我必须承认这是一个缺点,您的表示/服务层将泄漏到您的持久性方法中:例如,您将具有getCourseWithTeacher()方法和getCourseWithStudents()方法,在这两种情况下,这两种关系都会渴望得到(第一种情况下的老师,另一种情况下的学生)。

但是,这种方法只允许您对每个屏幕/服务执行一次查询,并且可以干净地管理异常。

我只看到OpenSessionInView的一个用例:如果您有一堆初级Hibernate开发人员,没有时间正确地向他们解释整个过程,也没有性能问题(可能是由于非常简单的实体模型或非常简单的屏幕),那么这是一个很好的权衡(但仍不是一种模式)。 一旦您脱离此配置,它将带您进入痛苦的世界...

只要您与OpenSessionInView没有任何关系,我会对您提供的关于优势的投入和争论感兴趣,只要它与以下内容无关:

  • 我一直都做得很成功
  • 我从来没有任何问题
  • XXX在YYY图书中为OpenSessionInView做广告(是的,我知道加文·金(Gavin King),但不应阻止任何人自己思考)。 它的一个变体是:ZZZ框架有一个可以做到这一点的类(我也了解Spring)

如果您对LazyInitializationException有其他创造性的见解,我也很感兴趣。

翻译自: https://blog.frankel.ch/the-opensessioninview-antipattern/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值