The Open Session In View Anti-Pattern

(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 projections are better suited for read-only data sets.

Entities are very useful for read-write transactions because you can benefit from the automatic dirty checking mechanism while preventing lost updates phenomena in 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 associations because, 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.LAZY attribute.

However, a LAZY association needs the Session to 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 LazyInitializationException is thrown.

For read-only views, when using DTO projections, we have to manually choose the child associations properties too, therefore, the LazyInitializationException cannot 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-many relationship, JOIN FETCH directive is the best way of initializing the associations that are going to be needed in the view layer. For multiple one-to-many associations, 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 OpenSessionInViewFilter calls the openSession method of the underlying SessionFactory and obtains a new Session.
  • The Session is bound to the TransactionSynchronizationManager.
  • The OpenSessionInViewFilter calls the doFilter of the javax.servlet.FilterChain object reference and the request is further processed
  • The DispatcherServlet is called, and it routes the HTTP request to the underlying PostController.
  • The PostController calls the PostService to get a list of Post entities.
  • The PostService opens a new transaction, and the HibernateTransactionManager reuses the same Session that was opened by the OpenSessionInViewFilter.
  • The PostDAO fetches the list of Post entities without initializing any lazy association.
  • The PostService commits the underlying transaction, but the Session is not closed because it was opened externally.
  • The DispatcherServlet starts rendering the UI, which, in turn, navigates the lazy associations and triggers their initialization.
  • The OpenSessionInViewFilter can 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 Connection as 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 generated requires 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 @BatchSize for fetching associations in batches, and FetchMode.SUBSELECT to 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 Book and Video Courses as 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 projection forces 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.

Subscribe to our Newsletter

* indicates required
10 000 readers have found this blog worth following!

If you subscribe to my newsletter, you'll get:
  • A free sample of my Video Course about running Integration tests at warp-speed using Docker and tmpfs
  • 3 chapters from my book, High-Performance Java Persistence, 
  • a 10% discount coupon for my book. 
Get the most out of your persistence layer!

Advertisements

17 thoughts on “The Open Session In View Anti-Pattern

  1. This is the first thing that comes up on google when searching for open session in view and it makes me sad because I think this article is not accurate in many ways and also makes many assumptions.

    The real issue has nothing to do with the Open Session In View pattern. The real issue is that round trips to the database are extremely costly. You can create queries in a loop with business layer fetching just as easily as with OSIV or any other pattern.

    “It is only the business layer responsibility to fetch all the data that’s necessary for a particular business use case”

    For one thing, you can have a business layer do your fetching and still use a request scoped session (OSIV). I don’t see how one precludes the other. Having each call to your business layer open and close it’s own session can potentially create a query for information already fetched from a prior use case which is common and can be very costly. OSIV can prevent unnecessary queries because it effectively caches objects in request scope. Also, the business layer often does not have enough information to fetch exactly what is needed this is where lazy initialization can save the day. You may only need to fetch a single child record from a list of parents but you don’t know which one until you know. Lazy initialization can make this simple and possibly save the business layer loading too much data.

    “The service layer opens and closes a database transaction, but afterward, there is no explicit transaction going on”

    Again I’m not sure what this has to do with OSIV. Who’s to say there is no explicit transaction? If you need one in the UI rendering phase make one.

    “Last but not least, the database connection is held throughout the UI rendering”.

    My understanding is that in most cases the default release mode for hibernate will be AFTER_STATEMENT which means the connection is released after every statement obviously and not “held throughout” UI rendering.

    In summation, I don’t think the arguments in this article hold water. OSIV can be very effective and very high performance. The key to performance is generally LESS queries to the database. Monitor this by turning on Hibernate’s show_sql. Make sure the output makes sense and look for ways to remove EVERY query you can and DO NOT query the database in a loop EVER.

    1. The real issue has nothing to do with the Open Session In View pattern. The real issue is that round trips to the database are extremely costly. You can create queries in a loop with business layer fetching just as easily as with OSIV or any other pattern.

      No, it’s not. There are many aspects that can lead to performance issues. So many, that you can write a 450 pages book.

      Database roundtrips is just one aspect. Just like fetchcing too much data is another. Or, holding onto the database connection longer than necessary is another.

      For one thing, you can have a business layer do your fetching and still use a request scoped session (OSIV). I don’t see how one precludes the other.

      So what’s the gain of using OSIV anyway in this scenario? If you fetch all the data in the boundaries of the service layer,
      you don’t need OSIV at all.

      Having each call to your business layer open and close its own session can potentially create a query for information already fetched from a prior use case which is common and can be very costly.

      What exactly is the “use case” in this phrase? OSIV is bound to your request, that’s all. The database caching or second-level cache works the same with or without OSIV.

      OSIV can prevent unnecessary queries because it effectively caches objects in request scope.

      No, it can not. If the data is already fetched in the business layer, OSIV does not save you anything.

      Also, the business layer often does not have enough information to fetch exactly what is needed this is where lazy initialization can save the day.

      Of course, it does. That’s what design is all about when it comes to software development.

      You may only need to fetch a single child record from a list of parents but you don’t know which one until you know.
      Lazy initialization can make this simple and possibly save the business layer loading too much data.

      Lazy initialization works the same even when you don’t use OSIV.
      Of course, you are talking about the case when you push entities into the View layer instead of DTOs, which,
      for read-only projections, is another Anti Pattern.

      Again I’m not sure what this has to do with OSIV. Who’s to say there is no explicit transaction? If you need one in the UI rendering phase make one.

      Then, instead of one transaction, you would still have two, right? And, holding the DB transaction and the associated connection while the UI renders
      doesn’t sound like you are wasting connections when you should have to?

      My understanding is that in most cases the default release mode for hibernate will be AFTER_STATEMENT which means the connection is released after every statement obviously and not “held throughout” UI rendering.

      That’s onlly valid for JTA, not for RESOURCE_LOCAL. Check out this optimization wwe have added into Hibernatehttps://vladmihalcea.com/why-you-should-always-use-hibernate-connection-provider_disables_autocommit-for-resource-local-jpa-transactions/, by the way.

      In summation, I don’t think the arguments in this article hold water.
      OSIV can be very effective and very high performance.

      No, it’s not. There’s nothing about OSIV that leads to high-performance.
      Just because you used it before without thinking of how the connection and transactions are handled behind the scenes,
      it does not mean that it’s a good idea.

      The key to performance is generally LESS queries to the database. Monitor this by turning on Hibernate’s show_sql.

      Again, this is one of the many optimizations that you can do. And, the Hibernate logging is a nice,
      but datasource-proxy is awesome.

      Make sure the output makes sense and look for ways to remove EVERY query you can and DO NOT query the database in a loop EVER.

      Which does not have anything to do with OSIV.

      For more arguments about why OSIV is wrong, here’s a GitHub issue which led to generating a warning when OSIV is enabled in Spring Boot 2.

      1. I’ve educated myself on the topic of OSIV and I’ve read the GitHub you pointed out. I have also created applications which handle more requests per second than Wikipedia and on less hardware. I have profiled and optimized many application and have a detailed knowledge of how transactions and connections work.

        I have also read a whole lot of hibernate code and used many “patterns” that were designed by the author of hibernate Gavin King. Who, I am sure you know did design a 2 transaction per request style framework called Seam, which had some problems but was pretty amazing!

        I am a performance junky as you seem to be! We obliviously have a difference of opinion. I don’t think you have seriously considered my arguments so I will leave you to your opinion.

        P.S.

        Why would anyone making serious applications not be using JTA? Also, it might be good to mention such caveats in your argument against OSIV.

      2. At Devoss France, I was talking to some of my Hibernate colleagues that were involved with Seam as well, and they were also very surprised about my views on OSIV because they have never thought of it from the DB perspective.

        Form the application developer perspective, OSIV is very convenient. But, convenience comes at a price, and for OSIV, it’s not justified since you can easily address the root problem, which is:

        • either the entities are fetched exclusively, even when a DTO projection is more efficient
        • or the Service layer is just a thin wrapper over the DAO, delegating the fetching logic to the View layer

        Why would anyone make serious applications not be using JTA?

        Because you don’t need JTA if you only work with a single DataSource. For instance, even if JTA comes with 1PC optimization,
        there’s still an associated overhead to XA transaction than to RESOURCE_LOCAL.

        I studied Bitronix Transaction Manager a lot and provided some improvements for monitoring, and while analyzing it,
        I came to realize that the Tx logging and the associated internal synchronization takes its toll.

        JTA is useful when you need consensus over 2 or more XA resources, but, if you only operate on one DataSource at a time,
        then it will not buy you anything.

        More, the heuristic approach to handling recovery of non-committing Tx whose XAResource fails to acknowledge the prepared-but-not-committed Tx after recovery does not give you a 100% proof, as many devs expect from JTA.

        JTA is popular when using Java EE. But, it’s quite rare when you are using Spring.

  2. And for a longer running task, where several entities are going to be updated and the UI will poll to reflect the status changes in those entities, how does one effectively do this? A READ_UNCOMMITTED transaction scope (not what I would typically do). Spring doesn’t seem to afford the opportunity to commit a transaction for work on a particular entity in a collection being iterated over, without also closing the session and then leading to the LazyInitializationException

  3. Hello Vlad,
    If an application uses OSIVFilter, when using SessionFactory.getCurrentSession in the request lifecycle
    will that session span in multiple requests? I mean if I evict an object from that session any OTHER concurrent requests that may have modified the object’s properties lose their modifications due to the evict ?

    1. If an application uses OSIVFilter, when using SessionFactory.getCurrentSession in the request lifecycle
      will that session span in multiple requests?

      If the application uses OSIV, which is a bad choice anyway, then it’s the job of the OSIV implementation to handle the Session registration so that SessionFactory.getCurrentSession gives the same instance while being inside the life cycle of the Web Filter that implements OSIV.

      The session should never span over multiple requests. That’s not the goal for OSIV. That’s what @PersistenceContext(type = PersistenceContextType.EXTENDED) would give you in a Java EE application that uses Stafeul EJB.

      I mean if I evict an object from that session any OTHER concurrent requests that may have modified the object’s properties lose their modifications due to the evict ?

      As I explained in my book, High-Performanace Java Persitence, the Session is single-threaded. If you use OSIV, the Session is bound to an HttpRequest, which should also be single-threaded.

      If you bind the Session to the HttpSession, or you use @PersistenceContext(type = PersistenceContextType.EXTENDED) and expose the Session to multiple threads, then you are in trouble.

      Now, if you evict an entity, the entity will be detached and no further synchronization will be done. So, you don’t lose any changes until you dereference the entity. You lose durability for those changes.

      1. Thanks Vlad,
        I know that this OSIVFilter should not be used but the application is designed like this and a big change is not scheduled very soon. My worries were that if no further synchronization will be done in that session after the evict this will affect other requests that use the same object (same database table row) at the same time.

      2. If you are sharing the Session or thee entities between multiple concurrent requests, then an unforeseen application architecture refactoring will soon be justified.

        The only way to fix it is to avoid sharing entities, proxies, Session and EntityManager because they are not guaranteed to be thread-safe, so strange bugs will lurk when you least expect them.

Leave a Reply

Your email address will not be published. Required fields are marked *