@Thiago

I am absolutely correct here. The LazyLoadingException is indeed resulting
from a Transactional problem. The lazy loading has to be done inside the
very same transaction unless you reattach the entity for the next
transaction. On reattach hibernate reassures the entity has not changed by
looking for a version or a complete reload the current state and comparing
it to the actual state of the entity you reattach.

I checked the code and find that on commit the persistence context of the
session gets cleared only in the EJB3 scenario which is a kind of weired.
Beside this on afterTransactionCommit only the locks gets downgraded
/removed and the insertion keys collection to allow deferred flushing is
cleared. But there are some other stuff going on so

But beside this the hibernate documentation about lazy loading states this:

"Since the permissions collection was not initialized when the Session was
closed, the collection will not be able to load its state. *Hibernate does
not support lazy initialization for detached objects*. This can be fixed by
moving the code that reads from the collection to just before(!) the
transaction is committed. "

So Hibernate itself states that lazy loading has to happen inside the very
same transaction. Since we are used to using a single transaction per
request pattern we are usually not aware of this fact.

Also note that hibernate if I am correctly uses automatically attachment so
the entity is reattached before the lazy loading is taking place inside the
next transaction. This makes this @commitAfter behavior so harmful. Most of
the implications are hidden from the developer.

I found something that is interesting on the reattachment:

/**
 * When an entity is passed to update(), we must inspect all its
collections and
 * 1. associate any uninitialized PersistentCollections with this session
 * 2. associate any initialized PersistentCollections with this session,
using the
 *    existing snapshot
 * 3. execute a collection removal (SQL DELETE) for each null collection
property
 *    or "new" collection
 *
 * @author Gavin King
 */
public class OnUpdateVisitor extends ReattachVisitor {

The fun is the reattachvisitor which is going along a entity graph and
reattaches everything. I will also check the update implementation. Here
you have something like this

public boolean reassociateIfUninitializedProxy(Object value) throws
MappingException {
        if ( value instanceof ElementWrapper ) {
            value = ( (ElementWrapper) value ).getElement();
        }

        if ( !Hibernate.isInitialized(value) ) {
            HibernateProxy proxy = (HibernateProxy) value;
            LazyInitializer li = proxy.getHibernateLazyInitializer();
            reassociateProxy(li, proxy);
            return true;
        }
        else {
            return false;
        }
    }

So Hibernate seams to handle proxies (as used for lazy loading) in a way
that everytime a proxy is encountered it ensures that the proxy is using
the current session. This can be seen as a reattachment by itself. This
happens even if the proxy is already from this session. There seams to be
no distinction. So if you use two sessions and mix them up you end up
having entities being reattached all the time.

But I also found no evidence for a good check of reassurance that the
entities information are still valid. They are deferred to version
comparism on save/update so the current hibernate session implementation
allows you to work on stale data. This was quite interesting. So to sum it
up.

Transactional context is all that matters. If you use a managed
transaction(JTA) your session is cleaned up after transaction ends. If you
use SpringFramework your session is closed after transaction is end. If you
use EJB3 (JPA) the session is cleaned up if the transaction is committed.

But (!) If you use a hibernate only transaction the session is not cleaned
up but only everything related to locks etc. So if you commit and reenter,
everything gets logically reattached or even hibernate pretents that
everything is still valid. This is a big problem. I will note it down. In
the end the HibernateManagerImpl should ensure that the session factory is
set to autoClean to clean the persistent context of every session after the
transaction is committed since that is the only way to be sure. And also
the @CommitAfter problem would have been spotted right on spot. I never
thought it is possible to work on stale data this way. There is a reason
why the JPA / EJB3 requires a autoClear after each transaction commit.

Quite interesting. And the reason why I donated 20min of code reading to
this. The information I used are form what I did 2008/9 so It might have
changed or something. I only think in terms of JPA right now so It was
funny to see something like happening.

Maybe Hibernate has some other measures in place to avoid this stale data
scenario. If I remember correctly the hibernate documentation states that
outside the transaction things can be stale and invalide and are only
checked in terms of versioning of entities. So I guess here is the reason
why hibernate wanted us to use versioning for long going conversations
(e.g. business cases that span multiple transactions) to ensure entity
integrity.

So play it right and put everything into a single transaction.







2013/9/3 Boris Horvat <horvat.z.bo...@gmail.com>

> hm...I see your point, then I will drop this idea then.
>
> Thanks
>
>
> On Tue, Sep 3, 2013 at 12:20 AM, Thiago H de Paula Figueiredo <
> thiag...@gmail.com> wrote:
>
> > On Mon, 02 Sep 2013 18:01:06 -0300, Boris Horvat <
> horvat.z.bo...@gmail.com>
> > wrote:
> >
> >  Hi Thiago,
> >>
> >
> > Hi!
> >
> >
> >  sorry for continuing this thread but I was wondering is it possible to
> >> somehow provide some automated ways in tapestry to reattach the session.
> >>
> >
> > Just use Session.merge() before using an entity. Or create a session
> > persistence strategy that does the merge (reattaching) automatically if
> > that doesn't exist already. Handling this exception and somehow merge the
> > entity and going ahead as if the exception didn't happen, AFAIK, is
> > impossible due to the way Java and other languages work. Unless you're
> > thinking of restarting the request handling, something IMHO is too ugly
> of
> > an hack instead of doing the right thing (merging the object into the
> > session in some way or another).
> >
> >
> >  Something like handle uncaught exceptions in normal applications.
> >>
> >
> > What do you mean by normal applications?
> >
> >
> >  If there is such an event I guess it should be possible to somehow have
> >> this
> >> automated, no?
> >>
> >
> > Catching the exception is easy, trying to do something beyond reporting
> > and logging it it's the hardest part by far.
> >
> >
> > --
> > Thiago H. de Paula Figueiredo
> >
> > ------------------------------**------------------------------**---------
> > To unsubscribe, e-mail: users-unsubscribe@tapestry.**apache.org<
> users-unsubscr...@tapestry.apache.org>
> > For additional commands, e-mail: users-h...@tapestry.apache.org
> >
> >
>
>
> --
> Sincerely
> *Boris Horvat*
>

Reply via email to