Using JPA entities in JSF. Which is the best strategy to prevent LazyInitializationException?

后端 未结 6 1904
执念已碎
执念已碎 2020-11-28 11:48

Would like to hear experts on best practice of editing JPA entities from JSF UI.

So, a couple of words about the problem.

Imagine I have the persisted object

6条回答
  •  庸人自扰
    2020-11-28 11:59

    For Hibernate >= 4.1.6 read this https://stackoverflow.com/a/11913404/3252285

    Using the OpenSessionInView Filter (Design pattern) is very usefull, but in my opinion it dosn't solve the problem completely, here's why :

    If we have an Entity stored in Session or handled by a Session Bean or retrieved from the cache, and one of its collections has not been initialized during the same loading request, then we could get the Exception at any time we call it later, even if we use the OSIV desing pattern.

    Lets detail the problem:

    • Any hibernate Proxy need to be attached to an Opened Session to works correctly.
    • Hibernate is not offering any tool (Listener or Handler) to reatach the proxy in case his session is closed or he's detached from its own session.

    Why hibernate dosn't offer that ? : because its not easy to identify to which Session, the Proxy should be reatached, but in many cases we could.

    So how to reattach the proxy when the LazyInitializationException happens ?.

    In my ERP, i modify thoses Classes : JavassistLazyInitializer and AbstractPersistentCollection, then i never care about this Exception any more (used since 3 years without any bug) :

    class JavassistLazyInitializer{
         @Override
         public Object invoke(
                            final Object proxy,
                            final Method thisMethod,
                            final Method proceed,
                            final Object[] args) throws Throwable {
                if ( this.constructed ) {
                    Object result;
                    try {
                        result = this.invoke( thisMethod, args, proxy );
                    }
                    catch ( Throwable t ) {
                        throw new Exception( t.getCause() );
                    }           
                    if ( result == INVOKE_IMPLEMENTATION ) {
                        Object target = null;
                        try{
                            target = getImplementation();
                        }catch ( LazyInitializationException lze ) {
                  /* Catching the LazyInitException and reatach the proxy to the right Session */
                        EntityManager em = ContextConfig.getCurrent().getDAO(
                                            BaseBean.getWcx(), 
                                            HibernateProxyHelper.getClassWithoutInitializingProxy(proxy)).
                                            getEm();
                                    ((Session)em.getDelegate()).refresh(proxy);// attaching the proxy                   
                        }   
                        try{                
                            if (target==null)
                                target = getImplementation();
                                .....
                        }
            ....
         }
    

    and the

    class AbstractPersistentCollection{
    private  T withTemporarySessionIfNeeded(LazyInitializationWork lazyInitializationWork) {
            SessionImplementor originalSession = null;
            boolean isTempSession = false;
            boolean isJTA = false;      
            if ( session == null ) {
                if ( allowLoadOutsideTransaction ) {
                    session = openTemporarySessionForLoading();
                    isTempSession = true;
                }
                else {
        /* Let try to reatach the proxy to the right Session */
                    try{
                    session = ((SessionImplementor)ContextConfig.getCurrent().getDAO(
                            BaseBean.getWcx(), HibernateProxyHelper.getClassWithoutInitializingProxy(
                            owner)).getEm().getDelegate());             
                    SessionFactoryImplementor impl = (SessionFactoryImplementor) ((SessionImpl)session).getSessionFactory();            
                    ((SessionImpl)session).getPersistenceContext().addUninitializedDetachedCollection(
                            impl.getCollectionPersister(role), this);
                    }catch(Exception e){
                            e.printStackTrace();        
                    }
                    if (session==null)
                        throwLazyInitializationException( "could not initialize proxy - no Session" );
                }
            }
            if (session==null)
                throwLazyInitializationException( "could not initialize proxy - no Session" );
            ....
        }
    ...
    }
    

    NB :

    • I didn't fix all the possiblities like JTA or other cases.
    • This solution works even better when you activate the cache

提交回复
热议问题