PDA

View Full Version : Why OpenSessionInViewFilter is misleading and useless in most cases


infinity2heaven
07-18-2007, 11:55 AM
I might be wrong but this is my understanding.

There has been so much discussion about this Pattern but I'm surprised to see how blogs and articles embrace this pattern as if it's a panacea to solve lazy load exception of Hibernate. (and everything else). The ironic reality is OSIV works only within a request.

Yes, A single Request.

Consider this example.

User has a Tree model with nodes, children in the view or a single complex form which need to dynamically load associations based on user triggers. If you're using Spring MVC, this entire object could be your command object and is stored on HttpSession as well. Typically what the user wants is to load the object once and based on the user interaction, on a need-basis, load the collection objects. But as this is going to be another request each time, a new Hibernate Session is created, perhaps wrapped under a transaction and you get LazyInitialiationException as it is now two different Sessions.

As long as your lazy associations get initialized within the original transaction, there is no need to perform lazy loading in your views.
And if you anyway wanted to see all collections in the first request itself, why do you need to set lazy=true and add OSIV in the first place? (It's as good as having lazy=false). The point is, I think "lazy=true" is inherently designed for larger use cases which almost involve multiple http requests. OSIV is misleading in this respect that it doesn't serve the purpose. Not only that - the terms 'single session mode' and 'deferred close' add more confusion to the developers as they don't necessarily add a new feature but merely do not open a session but close all sessions in the sessionFactory registered as deferred. Probably helps if you want multiple sessions in a transaction. But then, it still works withing a SINGLE request

I'm still yet to see a blog or article on these forums on how anyone has solved this problem. Detached Criteria? Reattaching objects sounds cool but anyone has a working code generic enough to make it a pattern or a template method for the controllers?

Would like to know if somebody shares my views too and what is the right approach to solve this. An idea similar to OpenSessionInFlow (http://opensource.atlassian.com/projects/spring/browse/SWF-92)would help

PS: Going by the name, I think it should be called "OpenSessionInRequest" , I'd buy that!

pmularien
07-18-2007, 02:22 PM
I agree with your use case of maintaining a complex object in the session, and working with it through a series of pages doesn't fit with OSIV, however I think OSIV is meant to solve a different type of problem.
As long as your lazy associations get initialized within the original transaction, there is no need to perform lazy loading in your views.
IMO this is exactly the problem that OSIV is meant to solve. In many cases, especially with extremely dense and complex object structures, you don't want to have to explicitly initialize entire subtrees when they may not be used in a particular view. OSIV allows lazy loading of collections to work as expected, that is, collections are loaded when they are used and not sooner.

That said, the use of OSIV does break some tenets of separation of concerns and really breaks transactional semantics if you're using TX interceptors below the controller level of your Spring MVC app.
I'm surprised to see how blogs and articles embrace this pattern as if it's a panacea to solve lazy load exception of Hibernate. (and everything else).
I actually had thought that OSIV was not recommended because it can potentially cause problems with separation of concerns, as I mentioned. Reliance on OSIV can also make it hard to match up non-web-based unit tests with actual functionality in the web-based application.

As I said, I do agree that what you're describing would be useful, but I don't see why you can't get the functionality you're describing by reattaching the session-based object in formBackingObject (or in the appropriate method if you're using a wizard controller).

infinity2heaven
07-18-2007, 02:49 PM
but I don't see why you can't get the functionality you're describing by reattaching the session-based object in formBackingObject (or in the appropriate method if you're using a wizard controller

I've used a customized Wizard controller before and temporarily solved it (bad hack) but loading all collections in individual dao but doing a .size() on each child). But this scenario is not necessarily limited to a "page flow". Like I've mentioned, it could be a datastructure like Tree with rich set of objects under it, say on the left side of a view. What do you think the right pattern is, in this case? And if we bring in communication between this structure along with form elements( say a form on the right side of the view which displays the attributes of the object selected), things get really messy while manipulating detached objects with newly loaded objects.

What I am looking for is a generic solution (if any) to solve this rather typical use case along with OSIV as I still would like to have it for it's limited solutuion.

Saying "use detached criteria ...there" sounds simple on paper until someone has actually implemented this over a large set of use cases.

Any suggestions?

Jörg Heinicke
07-18-2007, 08:17 PM
OSIV allows lazy loading of collections to work as expected, that is, collections are loaded when they are used and not sooner.

But probably not the collection at once. Another downside of OSIV is the tend to initialize object by object in the collection which can extremely slow down the application if you don't take care.

Jörg

infinity2heaven
07-19-2007, 10:07 AM
Not sure if I quite understand your statement. Could you be more specific?

Jörg Heinicke
07-20-2007, 12:13 AM
You iterate over the collection of non-initialized objects. For each object there is one database statement done. Something like "select * from table where id=1" and so on instead of once just "select * from table".

Jörg

jglynn
07-20-2007, 09:58 AM
Commonly referred to as the "N+1 selects" issue.

infinity2heaven
07-20-2007, 11:00 AM
Thats a surprise! I didn't know that OSIV simulates a N+1 selects problem and it isn't apparent from Hibernate's reference (http://www.hibernate.org/43.html)either.

karldmoore
07-20-2007, 12:19 PM
That's one of the reasons I'm not a huge fan of OSIV, it's seductively easy to get up and running and you never have to worry about loading the entities within that request. This means you get away without thinking about the issues involved.

infinity2heaven
07-20-2007, 12:42 PM
Hey karldmoore, you're back again., interesting to see that you've added another 3000 posts since the last time we spoke!

I still am waiting for reply in this thread for a recommended pattern for the use case given in the original post. (lazyload, multiple requests - a generic solution)

PS: Hope this thread doesn't turn out to be a zombie like all the other OSIV threads

pmularien
07-20-2007, 01:58 PM
You iterate over the collection of non-initialized objects. For each object there is one database statement done. Something like "select * from table where id=1" and so on instead of once just "select * from table".

Jörg
This can be mitigated with adjustments to hibernate settings, IIRC.

infinity2heaven
07-20-2007, 02:09 PM
This can be mitigated with adjustments to hibernate settings, IIRC


Would appreciate more info on this ...

karldmoore
07-20-2007, 03:26 PM
Hey karldmoore, you're back again., interesting to see that you've added another 3000 posts since the last time we spoke!

Has it been that long :).

I still am waiting for reply in this thread for a recommended pattern for the use case given in the original post. (lazyload, multiple requests - a generic solution)

The concept of a flow and therefore OpenSessionInFlow seems to be a good idea to me. You basically want to keep the Session open for the lifetime of the flow, therefore defering closing the Session until you've finished what you were doing.

PS: Hope this thread doesn't turn out to be a zombie like all the other OSIV threads

Have you tried the Hibernate forums, there might be more information there.

jglynn
07-20-2007, 04:21 PM
Would appreciate more info on this ...

Hibernate fetching strategies. (http://www.hibernate.org/hib_docs/reference/en/html/performance.html)

Typically I use subselect fetching.

Regarding OSIV; my beef is mostly with regards to the inability to re-attach an object to the new session. As a result, binding must occur against a new object (retrieved from the database) because you cannot bind against the object you got in the previous request. Reason being, you'll be unable to persist that object as it's still tied to the previous session which has since been closed. Not only is this useless overhead, but it creates all sorts of problems when you'd like to take advantage of things like hibernate versioning for example.

Jörg Heinicke
07-20-2007, 10:00 PM
Commonly referred to as the "N+1 selects" issue.

Oh, thanks for the name. Might simplify explanation the next time :-)

Jörg

Jörg Heinicke
07-20-2007, 10:06 PM
This can be mitigated with adjustments to hibernate settings, IIRC.

Yes, you can set the batch size (http://www.hibernate.org/hib_docs/v3/reference/en/html/collections.html#collections-mapping) on a collection mapping. So it gets an 1 + N/batch size issue. That's why I didn't formulate it too absolute in my first answer (http://forum.springframework.org/showthread.php?t=41582#4).

Jörg

Jörg Heinicke
07-20-2007, 10:32 PM
Regarding OSIV; my beef is mostly with regards to the inability to re-attach an object to the new session. As a result, binding must occur against a new object (retrieved from the database) because you cannot bind against the object you got in the previous request. Reason being, you'll be unable to persist that object as it's still tied to the previous session which has since been closed. Not only is this useless overhead, but it creates all sorts of problems when you'd like to take advantage of things like hibernate versioning for example.

As far as I understand this is not a problem with OSIV but with Hibernate in general - as long as you don't have anything like extended (http://forum.springframework.org/showthread.php?t=32270&page=2) sessions (http://forum.springframework.org/showthread.php?t=24174&page=2#13). I still don't have the silver bullet (http://forum.springframework.org/showthread.php?t=24174&page=3#23).

Jörg

jglynn
07-21-2007, 02:06 PM
Very true, I suppose I mistakenly identify it with OSIV because that's the pattern I'm using but you're right, this is a Hibernate issue.

A comment you made in another thread That's why a detached object should just lazily reattach when necessary and a session is available. Like I provide a transaction declaratively and transparently I would do it with a session is precisely the functionality I desire.

berkum
08-28-2007, 08:12 PM
Am I the only one thinking that the OSIV pattern is more an anti-pattern than a pattern ?

It seems to me that it breaks a basic design principle. A layer should not rely on layers above it and should only know of services in its own layer or sublayers.

In OSIV, the business or eis layer (data layer) is dependant on the web layer. Isn't that completely wrong ?

What I see in OSIV is a big patch for projects that have developed with lazy attribute to false for every collection thinking that they would improve performance at the end of the project. Then you would need OSIV, otherwise you would have a bunch of LazyLoadingException. But this is a patch...

Another point, you are putting hibernate stuff in the presentation layer. This layer should not even be aware that you are using hibernate.

Your services are not reusable through web services (might not be a big issue) since there is no session available.

Also, by using the OSIV, you will most probably generate N+1 selects as mentioned. You should be opmimizing your fetching either through join="fetch" or join="subselect" among possibilities.

There would be many reasons why not to use OSIV, but as previously mentioned, simply because your business layer relies on your presentation layer is a good enough reason for me to avoid it. At that point, let's have all classes in the presentation layer...

Your opinion would be more than welcome.
Regards,
Alain Bergeron

Jörg Heinicke
08-28-2007, 11:40 PM
In OSIV, the business or eis layer (data layer) is dependant on the web layer.

With the rather standard architecture with data access, service and web layer you suffer from the same "problem". The data access is "dependent" on the service layer. But in both cases it's not really a dependency, transactions are a cross-cutting concern.

What I see in OSIV is a big patch for projects that have developed with lazy attribute to false for every collection thinking that they would improve performance at the end of the project. Then you would need OSIV, otherwise you would have a bunch of LazyLoadingException. But this is a patch...

I can agree with this view.

Another point, you are putting hibernate stuff in the presentation layer. This layer should not even be aware that you are using hibernate.

OSIV has nothing to do with the presentation - or in other words, the presentation layer is still not aware at all that Hibernate is involved. It's still a cross-cutting concern and applied via a filter or an interceptor. If you do this on the web or the service layer doesn't make a difference IMO.

Also, by using the OSIV, you will most probably generate N+1 selects as mentioned. You should be opmimizing your fetching either through join="fetch" or join="subselect" among possibilities.

The patch character with the potential and likely negative side-effects outlined by you are the actual issues with OSIV. I would not care about on which layer it is actually applied otherwise.

Joerg

berkum
08-29-2007, 07:18 AM
OSIV has nothing to do with the presentation - or in other words, the presentation layer is still not aware at all that Hibernate is involved. It's still a cross-cutting concern and applied via a filter or an interceptor. If you do this on the web or the service layer doesn't make a difference IMO.



Even though the implementation is through ServletFilter, this is part of the servlet api. This for me is the presentation layer. Of course, application code need not be aware of this mecanism, still I don't like the idea of providing access to hibernate api in the web layer. This means other programmer can start calling hibernate api in their servlet, actions or else. And they will. This will lead very bad code.

Still, I got your point right. Thank you.