0

Hibernate LazyInitializationException JEE Environment

asked 2010-03-14 14:37:08 +0800

fbdo gravatar image fbdo
72 2

Hello list!

I'm having some difficulties configuring a plain JEE web application using ZK and Hibernate. I'm trying to configure the org.zkoss.zkplus.jpa.OpenEntityManagerInViewListener, but it depends on hibernate.cfg.xml, what is not my case. I'm using JPA and hibernate as my JPA provider. I already wrote a simple filter starting a UserTransaction on request, but this didn't work either. Do anyone has experience with this kind of environment? Can you share your config files?

Thanks in advance!

delete flag offensive retag edit

7 Replies

Sort by ยป oldest newest

answered 2010-03-14 15:34:20 +0800

caclark gravatar image caclark
1753 2 5
http://clarktrips.intltwi...

What's the scenario that you're getting the LIE? Is it on your initial data load or after that when you're paging down to some rows in a list/grid/combobox that were not displayed initially? The stack trace would be handy.

If it's the latter of the 2, the issue has long been discussed and there's a bit of mismatch between ZK and Hibernate lazy loading. ZK has the object for the item it's trying to render, but the Hibernate session has been closed and is therefore null in your proxy object. Me and others have run into this before. I have a solution that, while not the most elegant, is the only thing I've seen that works. Let me know if this is your scenario and I'll expound further. Also, if this is your problem, no amount of Open (Session|EntitiyManger)InView(Listener|Filter) will solve your problem. Unfortunately, my suspicions are that this is your case. I've written up some stuff to start a discussion and now might be the time to finish it and bring it forth.

link publish delete flag offensive edit

answered 2010-03-15 05:43:07 +0800

fbdo gravatar image fbdo
72 2

Hi caclark, thank you for your answer.

It's the second scenario. Bad news for me. I'm porting a Spring application to JEE platform, and I'm already too late. Im some of my Spring tests, looks like the LIE was under control, using the filters provided by the Spring team. Now, I can see a 2 alternatives:

1) Wait and see the results of this discussion.

2) Change my JPA provider to EclipseLink, and pray for all the LIE go away.

My question is: Is there a production ready solution almost finished to this problem, or the solution will be scratched now? What is the fastest path to take?

Again, thank you all, and I'm waiting for the results of this discussion.

link publish delete flag offensive edit

answered 2010-03-15 11:21:33 +0800

Khosro gravatar image Khosro
48

Hi Caclark,
If it is possible ,please describe how you solve this problem.
Khosro.

link publish delete flag offensive edit

answered 2010-03-15 11:50:07 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

updated 2010-03-15 11:52:09 +0800

The third method that i use and some EE guys who works with huge data and hibernate:

- load only what you can see on a page. So, use a DB paging.
- load all related data therefore in one shoot (in most cases it results in a better performance on the DB server to do in one task as in 20 tasks. Remember that there are other users too that will work on the DB. )

link publish delete flag offensive edit

answered 2010-03-16 04:08:41 +0800

edudant gravatar image edudant
219 1 1 1
zk.datalite.cz

Hi, some time ago I discussed this problem on this thread - see my conclusion at the end.

For our type of application (lot of forms) and ZK (Ajax, object hold on server between requests), lazy loading is a problem the developer has to think about all the time and sometimes solve quite complex problems.

IMHO the only good solution is to use flow managed persistence context aka JBoss Seam or Spring Web Flow. That is the feature I miss in ZK the most nowadays.

@Calcark - I'm looking forward to your solution

P.S. lot of threads ends with "recommendations" that lazy loading is not a problem, that you should now in advance, what you will need etc. For some kind of applications it is true. However something that is bothering the developer all the time and is often counter-intuitive, can't be ok. Btw. the author of Hibernate created Seam to solve this problem.

link publish delete flag offensive edit

answered 2010-03-17 07:38:23 +0800

caclark gravatar image caclark
1753 2 5
http://clarktrips.intltwi...

..just wanted to let everyone know I'm on vacation this week and doing real work: installing sprinkler systems in my and my neighbor's front yards. We're lucky that we get to write software for a living! :-)

I'll get back to this is a few days and we'll see what we can figure out. It'll take longer than I have time for right now.

link publish delete flag offensive edit

answered 2010-04-09 07:36:28 +0800

caclark gravatar image caclark
1753 2 5
http://clarktrips.intltwi...

updated 2010-04-09 07:37:29 +0800

Well, it took me longer to get back to it, but I finally have...


First, I want to acknowledge edudant's thread from roughly a year ago(http://www.zkoss.org/forum/listComment/7470). If you want good background on the topic and the solutions attempted, read that first.

Second, my use cases might be a bit more narrow than some others, so I don't know if my findings are more broadly applicable or not. YMMV

Third, you're going to do design at some point in your project. You're better off doing it up front! I've always been a big fan of MVC and separation of concerns. As it applies to ZK: use controllers (ZK's composers), don't use much zscript, use services to do your operations that in turn use DAO's or equivalent lower lever operations, use a domain model. This is a whole topic unto itself, but it gives you an idea of some of my motivations.

What is the problem?
The "short" answer:
1) domain objects have been retrieved via Hibernate
2) they have a lazy loaded attribute (a collection of children or a parent object) (henceforth called the proxied object)
3) the list/combo/grid row item associated with the domain object is not rendered initially
4) the user scrolls a page, ZK determines that it needs to render more items, the proxied object is referenced but there is no Hibernate session

The situation is that the proxied object is not only lazy loaded but also there is no Hibernate session attached to it, so it's also a detached object in Hibernate parlance. It and the Hibernate session became disconnected because ZK rendered the initial viewable rows in one thread (an event thread) and ended its execution, closing the Hibernate session. The subsequent items are rendered in a ZK AU thread. And this is where the disjoint occurs - ZK believes the objects are fully hydrated but Hibernate does not and tries to initialize them...but the session is gone and you get a LIE (there's some irony in that acronym).


What are the solutions

If you're supplying your own renderer it's pretty simple. I have a window that has a listbox that includes grouping. Since I have to supply my own renderer to handle grouping, I added a small piece of code in the render() method where it handles the detail items to load the object if need be:

        public void render(Listitem item, java.lang.Object data)
        {
...
            if ( item instanceof Listgroup )
            {
...  do my grouping stuff
            }
            else
            {
                vehicleRequestService.loadIfNecessary( ((VREquipment)data).getVehicleRequest() ) ;
...  add my list cells
            }
        }

where the vehicle request is the proxied object. This approach allows the renderer (a UI concern), to request the appropriate concern (vehicleRequestService in this case) to do what's necessary to hydrate the object. Here's what ultimately done in that call (in a DAO):
    public void loadIfNecessary(Object domainObject)
    {
        Session session = null ;
        
        try
        {
            session = getSessionFactory().getCurrentSession() ;
            if ( !session.contains( domainObject ) )
            {
                session.lock( domainObject, LockMode.NONE ) ;
            }
        }
        catch ( org.hibernate.NonUniqueObjectException exc)
        {
            session.merge(domainObject) ;
        }
        catch( org.hibernate.LazyInitializationException exc)
        {
            session.merge(domainObject) ;
        }
    }

The majority of the time, the "lock without locking" does the trick...sometimes the merge() methods are required. I haven't had time to fine tune this method more with more research. There might be a better/simpler/more logical way.


What if you're not supplying your own renderer? The solution is not nearly as easy...:-(

1) As edudant pointed out, probably the best solution is a flow managed persistence context aka JBoss Seam or Spring Web Flow. I haven't dug into either of those (yet). As long as those techniques can provide the benefits without memory leaks and without too many assumptions, I'm all ears.

2) Paging - I think Stephan's suggestion is pretty good. There are many times that I use paged data. However, this is not always reliable since the user can make the browser smaller and your page size > the viewable rows, so you're right back where we started...

3) Semi-lazy loading - Some people, as edudant pointed out, just suggest turning off lazy loading. That's throwing the baby out with the bath water. It eliminates any possibility of performance gains. What's semi-lazy loading? You set Hibernate to lazy load but on retrieval in your controller, access the proxied object to force a load while you're in the event thread. This removes the lazy loading benefits for this particular list, but not your entire application.

4) An enhancement to the ZK API to provide a way for standard renderers to notify a controller that it's about to render an item. There is RendererCtrl, but the doTry() in it does not have any parameters; you don't know what it's about to render. Here's a link to my enhancement request:
https://sourceforge.net/tracker/?func=detail&aid=2965457&group_id=152762&atid=785194. If we had something along those lines, we could do the same thing I did using my own renderer but in the context of the framework. I have a fairly simple delegating renderer for listboxes that basically steps in the execution path to do the loadIfNecessary( bean ) that I showed earlier and then calls the real renderer. I'll share it if anyone wants it. Supplying an implementor of the new interface to a listbox/combobox/grid before rendering is required would enable it to then supply that to its internal Renderer class so it can call back to the app. The class name could be set as a tag attribute or an instance set via Java during doAfterCompose().

    <listbox ... prerenderer="my.package.and.Class" >...</listbox>

or
    public void doAfterCompose( Component window )
        throws Exception
    {
        logger.info( "::doAfterCompose starting:" ) ;

        super.doAfterCompose( window ) ;

        listbox.setPrerenderer( myPrerenderer ) ;        

        logger.debug( "::doAfterCompose ending" ) ;
    }

Is this the most elegant solution? I don't know, but it's the only one I've seen that provides a hook by the framework into the app that allows it to then delegate to whomever is responsible for reconnecting the proxied object to a session. Maybe I overlooked something simple, but if so, we've at least started discussion on it.

link publish delete flag offensive edit
Your reply
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow

RSS

Stats

Asked: 2010-03-14 14:37:08 +0800

Seen: 1,580 times

Last updated: Apr 09 '10

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More