The Open Session In View Anti-Pattern - Vlad Mihalcea

标签: | 发表时间:2018-03-14 10:46 | 作者:
出处:https://vladmihalcea.com
(Last Updated On: February 22, 2018)

Introduction

The Open Session in View is an Anti-Pattern, and this post is going to demonstrate why it is so. First of all, let’s start with the Wikipedia definition of an Anti-Pattern:

An anti-pattern (or antipattern) is a common response to a recurring problem that is usually ineffective and risks being highly counterproductive.

A LazyInitializationException band aid

When using JPA and Hibernate, the Fetching policy can have one of the biggest impacts on application performance, and, as explained in my High-Performance JDBC presentation, you should always fetch just as much data you need to fulfil the requirements of a given business logic use case. Fetching too many columns than necessary has an impact, and that’s why entities are not good candidates for read-only views. In turn, DTO projectionsare better suited for read-only data sets.

Entities are very useful for read-write transactions because you can benefit from the automatic dirty checking mechanismwhile preventing lost updates phenomenain multi-request logical transactions.

Unfortunately, many enterprise applications don’t make this distinction, and they rely solely on entities for both read-only and read-write transactions. Not only that an entity has more columns than a custom DTO projection, but the entity might have associations as well. Entity associations are convenient because it allows the application developer to access joined relationships without even needing to write a query.

Hibernate comes with Proxies that allow the application developer to defer fetching until the association is needed. This is very useful, especially from a performance perspective. The worst thing to do is to use EAGER associationsbecause, once a relationship is set to be eagerly fetched, it cannot be changed to being fetched lazily on a per query basis. For this reason, many associations are configured with the FetchType.LAZYattribute.

However, a LAZY association needs the Sessionto be opened in order to initialize the Proxy. If the Persistence Context is closed, when trying to access a non-initialized LAZY association, the infamous LazyInitializationExceptionis thrown.

For read-only views, when using DTO projections, we have to manually choose the child associations properties too, therefore, the LazyInitializationExceptioncannot occur. For read-write transactions, entities might be fetched with the intention of being modified and saved at the end of the currently running workflow. These entities are prone to LazyInitializationException(s), so there are good ways and bad ways of dealing with this issue.

It is only the business layer responsibility to fetch all the data that’s necessary for a particular business use case. For many-to-one and one-to-one associations, as well as to at most one one-to-manyrelationship, JOIN FETCHdirective is the best way of initializing the associations that are going to be needed in the view layer. For multiple one-to-manyassociations, to avoid a Cartesian Product, it’s necessary to use secondary queries. These secondary queries can be fired when the association is accessed for the first time, which can be done with the Hibernate.initialize(proxy)utility.

Open Session In View takes a different approach. Instead of letting the business layer decide how it’s best to fetch all the associations that are needed by the View layer, it forces the Persistence Context to stay open so that the View layer can trigger the Proxy initialization.

OpenSessionInView

  • The OpenSessionInViewFiltercalls the openSessionmethod of the underlying SessionFactoryand obtains a new Session.
  • The Sessionis bound to the TransactionSynchronizationManager.
  • The OpenSessionInViewFiltercalls the doFilterof the javax.servlet.FilterChainobject reference and the request is further processed
  • The DispatcherServletis called, and it routes the HTTP request to the underlying PostController.
  • The PostControllercalls the PostServiceto get a list of Postentities.
  • The PostServiceopens a new transaction, and the HibernateTransactionManagerreuses the same Sessionthat was opened by the OpenSessionInViewFilter.
  • The PostDAOfetches the list of Postentities without initializing any lazy association.
  • The PostServicecommits the underlying transaction, but the Sessionis not closed because it was opened externally.
  • The DispatcherServletstarts rendering the UI, which, in turn, navigates the lazy associations and triggers their initialization.
  • The OpenSessionInViewFiltercan close the Session, and the underlying database connection is released as well.

At a first glance, this might not look like a terrible thing to do, but, once you view it from a database perspective, a series of flaws start to become more obvious.

The service layer opens and closes a database transaction, but afterward, there is no explicit transaction going on. For this reason, every additional statement issued from the UI rendering phase is executed in auto-commit mode. Auto-commit puts pressure on the database server because each statement must flush the transaction log to disk, therefore causing a lot of I/O traffic on the database side. One optimization would be to mark the Connectionas read-only which would allow the database server to avoid writing to the transaction log.

There is no separation of concerns anymore because statements are generated both by the service layer and by the UI rendering process. Writing integration tests that assert the number of statements being generatedrequires going through all layers (web, service, DAO) while having the application deployed on a web container. Even when using an in-memory database (e.g. HSQLDB) and a lightweight web server (e.g. Jetty), these integration tests are going to be slower to execute than if layers were separated and the back-end integration tests used the database, while the front-end integration tests were mocking the service layer altogether.

The UI layer is limited to navigating associations which can, in turn, trigger N+1 query problems. Although Hibernate offers @BatchSizefor fetching associations in batches, and FetchMode.SUBSELECTto cope with this scenario, the annotations are affecting the default fetch plan, so they get applied to every business use case. For this reason, a data access layer query is much more suitable because it can be tailored to the current use case data fetch requirements.

Last but not least, the database connection is held throughout the UI rendering phase which increases connection lease time and limits the overall transaction throughput due to congestion on the database connection pool. The more the connection is held, the more other concurrent requests are going to wait to get a connection from the pool.

Read-life stories

After a long debate, it’s good that Spring Boot issues a warning id the Open Session In View mode is active.

If you enjoyed this article, I bet you are going to love my Bookand Video Coursesas well.

Conclusion

The Open Session in View is a solution to a problem that should not exist in the first place, and the most likely root cause is relying exclusively on entity fetching. If the UI layer only needs a view of the underlying data, then the data access layer is going to perform much better with a DTO projection.

A DTO projectionforces the application developer to fetch just the required data set and is not susceptible to LazyInitializationException(s). This way, the separation of concerns is no longer compromised, and performance optimizations can be applied at the data access layer level since all statements are confined to the boundaries of the currently executing transaction.

link:
https://blog.frankel.ch/the-opensessioninview-antipattern/

相关 [the open session] 推荐:

The Open Session In View Anti-Pattern - Vlad Mihalcea

- -
An anti-pattern (or antipattern) is a common response to a recurring problem that is usually ineffective and risks being highly counterproductive.. When using JPA and Hibernate, the Fetching policy can have one of the biggest impacts on application performance, and, as explained in my.

session fixation攻击

- - 互联网 - ITeye博客
什么是session fixation攻击. Session fixation有人翻译成“Session完成攻击”,实际上fixation是确知和确定的意思,在此是指Web服务的会话ID是确知不变的,攻击者为受害着确定一个会话ID从而达到攻击的目的. 在维基百科中专门有个词条 http://en.wikipedia.org/wiki/Session_fixation,在此引述其攻击情景,防范策略参考原文.

Zookeeper的Session

- - 行业应用 - ITeye博客
介绍一下基于zookeeper的一些API的编程. 在此之前,我们先来熟悉一下相关知识:. Zookeeper的Session:. (1)客户端和server间采用长连接. (2)连接建立后,server产生session ID(64位)返还给客户端. (3)客户端定期发送ping包来检查和保持和server的连接.

TFO(tcp fast open)简介

- chenqj - pagefault
原创文章,转载请注明: 转载自pagefault. 本文链接地址: TFO(tcp fast open)简介. 这个是google的几个人提交的一个rfc,是对tcp的一个增强,简而言之就是在3次握手的时候也用来交换数据. 这个东西google内部已经在使用了,不过内核的相关patch还没有开源出来,chrome也支持这个了(client的内核必须支持).

Open API的资源集

- Rossoneri - 博客园-首页原创精华区
现在经常听到和使用到各种开放API,因此笔者对这些进行概要的汇总和整理,希望对有这些需求的有一定的参考价值. 什么是开放平台(Open Platform). 在互联网时代,把网站的服务封装成一系列计算机易识别的数据接口开放出去,供第三方开发者使用,这种行为就叫做Open API,提供开放API的平台本身就被称为开放平台.

惠普宣布Open webOS 1.0

- - Solidot
惠普按计划发布了开源版本WebOS的1.0正式版. Open webOS 1.0源代码已发布在GitHub上. 正式版加入了核心应用程序电子邮件和浏览器,支持 Enyo2. 惠普表示1.0版可移植到新设备上,称未来几个月会继续增强Open webOS,计划中的增强包括Qt5/WebKit2,开源多媒体和音频组件,BlueZ蓝牙堆栈,ConnMan网络管理,优化SysMgr渲染架构.

详解 Too many open files

- - 编程语言 - ITeye博客
 运行在Linux系统上的Java程序可能会出现"Too many open files"的异常情况,且常见于高并发访问文件系统,多线程网络连接等场景.         程序经常访问的文件、socket在Linux中都是文件file,系统需要记录每个当前访问file的name、location、access authority等相关信息,这样的一个实体被称为file entry.

Session机制解析

- - ITeye博客
虽然session机制在web应用程序中被采用已经很长时间了,但是仍然有很多人不清楚session机制的本质,以至不能正确的应用这一技术. 本文将详细讨论session的工作机制并且对在Java web application中应用session机制时常见的问题作出解答. 二、HTTP协议与状态保持.

session和cookie详解

- - ITeye博客
摘要:虽然session机制在web应用程序中被采用已经很长时间了,但是仍然有很多人不清楚session机制的本质,以至不能正确的应用这一 技术. 本文将详细讨论session的工作机制并且对在Java web application中应用session机制时常见的问题作出解答. 二、HTTP协议与状态保持.

nginx + memcached session 同步

- - 企业架构 - ITeye博客
squid 缓存疑问 问题归纳:. 1 squid 缓存的数据,何时过期,如何判断缓存的数据已经过期,如何把最新的数据缓入squid 并且替换掉旧的内容. 2 如何判断数据是否应该被缓存. 3 校验失败时,是否给出缓存中旧的内容. 上面的几个问题  都可以通过 squid中的 refresh_pattern 配置项 找到答案.