Page 1 of 3 123 LastLast
Results 1 to 10 of 24

Thread: Avoiding OpenSessionInView

  1. #1
    Join Date
    Feb 2006
    Posts
    13

    Default Avoiding OpenSessionInView

    Hi All,

    I have spent quite some time looking into why the OpenSessionInView filter is considered a bad idea. I haven't yet found a definitive answer (or set of answers) as to why this is so, but from what I've read it seems to be considered a bad idea because you're tying the view rendering to the database session, and there is no guarentee that the view (ie - the browser) will finish rendering properly (network connection may die, etc). Are there any other reasons why the OpenSessionInView filter is discouraged?

    Now, assuming that OpenSessionInView is a bad idea, I want to redevelop an application I made earlier to use the "correct" approach (ie - by not using the OpenSessionInView filter).

    So rather than doing the following in my view:

    Code:
    Employee employee = serviceLayer.getEmployee();
    String employerFirstName = employee.getManager().getFirstName();
    1. Do I have to change my code to dip into the service layer each time I have to rely on ORM:

    Code:
    Employee employee = serviceLayer.getEmployee();
    Manager manager = serviceLayer.getManagerForEmployee(employee);
    String employeeFirstName = serviceLayer.getFirstNameForManager(manager);
    with my serviceLayer implementation being:

    Code:
    public class MyServiceLayer {
      public Employee getEmployee() {
        return this.employeeDao.readSomeEmployee();
      }
    
      public Manager getManagerForEmployee(Employee employee) {
        Employee persistentEmployee = this.employeeDao.readById(employee.getId());
        return persistentEmployee.getManager();
      }
    
      public String getFirstNameForManager(Manager manager) {
        Manager persistentManager = this.managerDao.readById(manager.getId());
        return persistentManager.getFirstName();
      }
    
      ...
    
    }
    2. Or do I have to preload all values in the service layer and pass "built-up" model back:

    Code:
    Employee employee = serviceLayer.getEmployee();
    String employerFirstName = employee.getManager().getFirstName();
    with my serviceLayer implementation being the following:

    Code:
    public class MyServiceLayer {
      public Employee getEmployee() {
        Employee employee = this.employeeDao.readSomeEmployee();
        employee.getManager().getFirstName(); // just read it ...
        // .. and similarly read all other values I will need later on 
        // such as getLastName(), getAge(), and anything else
        
        return employee;
      }
    }
    Or would I do something completely different to get the data loaded in memory?

    I would really appreciate any help. I want to do this properly.

    ~gautam

  2. #2
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    OpenSessionInView is discourage not because the network connections may die (the page is rendered on the server before being send through the wire) but because the objects in the view might trigger a lot of database calls.
    Through lazy loading you don't care about what objects are initialized and if you have for example a list of lazy objects which you display along with some relationships, the view will make a lot of database calls to initialize each object and then, for each object the relationships.

    If you are not using OpenSessionInView, you have to initialize the objects before closing the session. The most common solution (and faster) is to know before hand what objects you need and use your specific ORM methods to force initialization (FETCH or Hibernate.initialize in case of HB).
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  3. #3
    Join Date
    Oct 2004
    Location
    Herndon, VA, US
    Posts
    648

    Default wait...

    Quote Originally Posted by costin
    OpenSessionInView is discourage not because ... but because...
    I thought OpenSessionInView was by far still "debatable". When did it get moved to the "discouraged" lot?
    --Jing Xue

  4. #4
    Join Date
    Feb 2006
    Posts
    13

    Default interesting ...

    wow costin i wasn't aware of the initialize method in the hibernate template. thanks! now what do you mean by "FETCH"?

    I've found one more reason why OSIV can possibly "discouraged": If you're accessing data via ORMs in your view and hibernate throws an exception along the way you'll see that exception in the actual view itself. Whereas if you accessed the domain model from the service layer preloaded with all needed dependencies any exceptions would have already been thrown earlier.

  5. #5
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    i wasn't aware of the initialize method in the hibernate template. thanks! now what do you mean by "FETCH"?
    See Hibernate reference documentation (19.1 fetching strategies).
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  6. #6
    Join Date
    Oct 2004
    Location
    Herndon, VA, US
    Posts
    648

    Default

    Quote Originally Posted by KENTOSI
    I've found one more reason why OSIV can possibly "discouraged": If you're accessing data via ORMs in your view and hibernate throws an exception along the way you'll see that exception in the actual view itself.
    It's not necessarily always the case. As long as the exception happens while the container is still buffering the output, i.e., nothing has been flushed into the output stream, a 500 error will be sent instead of a half-baked page.

    When a lazy-loading exception happens after some output has been flushed, it does look ugly in the client browser, but a lot of other things (remember all those ubercomplicated Struts or JSF tags?) during page rendering could cause exceptions to be thrown as well. If you don't ever want your user to see any stack trace, you'd have to come up with a more generic solution instead of to just stop using lazy-loading.

    Quote Originally Posted by KENTOSI
    Whereas if you accessed the domain model from the service layer preloaded with all needed dependencies any exceptions would have already been thrown earlier.
    My problem with having the service layer preloading dependencies is this - it makes the service layer extremely sensitive to presentation changes. Any changes you make to the views that require additional dependencies to be loaded will force you to go back and change the service layer. On the other hand, when some view changes make it no longer necessary to load some of the dependencies, would you go to the service layer to stop preloading them? Chances are you wouldn't, because you are never sure of whoever else is using the same service and just decide to "play it safe". (think of "you" not as just yourself, but all the people working on your project and who will work on it over the years)

    The bottom line is, those changes in the service layer are usually subtle, not reflected by any service API change, and often not well documented - I don't see a lot of people javadoc'ing "this, this, and that dependencies on the object returned are preloaded, while the rest aren't", let alone coming back to "duly" update it whenever they make changes.

    I'm not saying OSIV is perfect (as it does have the performance penalty as costin pointed out, and a can of other worms), but as far as this particular argument is concerned, between a brittle service layer that can't even sign off on a definitive behavior contract, or a view that occasionally serves the user an ugly stack trace? I think I'm going to go with the second.
    --Jing Xue

  7. #7
    Join Date
    Aug 2004
    Location
    Sydney
    Posts
    503

    Default

    For web applications, OSIV is good and should be encouraged, but it shouldn't be your primary method of ensuring data is loaded. You should make sure that you tune each call to load data, and OSIV will pick up anything you didn't eagerly load.

    You do something resembling either of the following to eagerly load data. If you have: controller -> service (use-case) -> business -> dao, then you can parameterize the paths for 2. (below) and provide the paths to hydrate in the service layer, meaning that you business logic and dao layer remain free from code specifically hydrating parts of the object graph.

    1.

    Code:
    session.createQuery("from Person p left join fetch p.phones");
    to load a person and their phone numbers, or

    2.

    Code:
    Criteria cr = session.createCriteria(Person.class).setFetchMode("phones", FetchMode.JOIN);
    cr.add(Restrictions.idEq(new Long(id)));
    cr.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

  8. #8
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    I agree with manifoldronin - in applications with rich web pages and a big domain model (think over 70 objects and hierarchies 7 levels deep) lazy loading is a must for reasonable performance. Once the application grows and the requirement swift, you can easily run into problems since your objects are not properly initialized. It all boils down to your environment and requirement.
    Once common procedure in practice was to use OSIV for getting the application running and tune the performance as soon as possible but too soon since the requirements were always changing.
    Note that if you initialize your objects, you can still use OSIV - it will just not be used. However, if you do not use it, you'll end up with an exception.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  9. #9
    Join Date
    Apr 2007
    Posts
    2

    Default

    For me one reason for not using OSIV filter is the design. Service layer and view layer are different things, and if in the future you need to access a service using SWING for example, the OISV won't work.

  10. #10

    Default

    i'm not even sure what to think of OSIV anymore. i don't care for the concept of it, it's very weird. who invented it? but in a way it does sort of make sense, after all when an http request comes in that is the point where you need to get ready to load data. i just don't like how it's web specific, if i ever need to strip this one app out of tomcat and write a swing client for it, i've got some work to do.

    but OSIV is working fantastically for me right now and has been for a long time. so i'll just keep using it i guess.

    also your users should never see a stack trace. most web frameworks should have some concept of a subclassable exception handler. ours logs it, emails the developers and takes the user to a semi-nice error page. and through some good integration testing, it's very rare that we get one of those emails anymore.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •