天天看點

Spring的OpenEntityManagerInViewFilter

在Java Web項目中使用Hibernate經常會遇到LazyInitializationException 。這是因為controller和model層(java代碼)将通過JPA的一些啟用了延遲加載功能 的領域(如用getRefrence() 方法或者在關聯關系中采用fetch=FetchType.LAZY )傳回給view層(jsp代碼)的時候,由于加載領域對象的JPA Session已經關閉,導緻這些延遲加載的資料通路異常。

這時就可以使用OpenEntityManagerInViewFilter來将一個JPAsession與一次完整的請求過程對應的線程相綁定。請看一段僞代碼:

Service{   
        entitymanager=context.getEntityManager();   
        if(entitymanager==null) context.put(factory,createEntityManager());   
        entitymangager=context.getEntityManager();   
        entitymanager.begin();   
        public void find(Integer productid){//除了這個方法外,其他都是通過AOP織入的   
            em.getReference(Product.class,productid));   
        }   
        entitymanager=context.getEntityManager();   
        entitymanager.commit();   
        entitymanager.close();   
}  

Service{
    entitymanager=context.getEntityManager();
    if(entitymanager==null) context.put(factory,createEntityManager());
    entitymangager=context.getEntityManager();
    entitymanager.begin();
    public void find(Integer productid){//除了這個方法外,其他都是通過AOP織入的
      em.getReference(Product.class,productid));
    }
    entitymanager=context.getEntityManager();
    entitymanager.commit();
    entitymanager.close();
}       

上面的僞代碼示範了如果我們想調用我們自己定義的一個find()方法,spring會在該方法的前後織入一些代碼來開始事物和關閉session。當view層調要用這個find()方法擷取的對象(由于采用了延遲加載模式,隻有到要使用到該對象的時候才會讓session去資料庫取)的時候,實際上session已經關閉了,不能再讓session擷取對象。

OpenEntityManagerInViewFilter會讓session一直到view層調用結束後才關閉,請看下面的僞代碼:

Filter{   
        doFilter(chain){   
            context.getEntityManager().open();   
            chain.doFilter(req,res){   
                xxxAction{   
                    execute(){   
                        Product product=service.find(productid);//此時該對象為遊離狀态,實際上并沒有在資料庫獲得值。   
                        req.setAttibute("Product",produxt);//這時候才到資料庫裡面去取值   
                        return mapping.findForward("product");   
                    }   
                }   
            }   
            context.getEntityManager().close()...   
        }   
    }  

Filter{
        doFilter(chain){
            context.getEntityManager().open();
            chain.doFilter(req,res){
                xxxAction{
                    execute(){
                        Product product=service.find(productid);//此時該對象為遊離狀态,實際上并沒有在資料庫獲得值。
                        req.setAttibute("Product",produxt);//這時候才到資料庫裡面去取值
                        return mapping.findForward("product");
                    }
                }
            }
            context.getEntityManager().close()...
        }
    }       
如果沒使用OpenEntityManagerInViewFilter,session會在service.find()方法後就被關閉,用了以後session在整個view層結束後才關閉。       

配置該filter的方法:在web.xml檔案中加入如下代碼

<filter>  
        <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>  
        <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>  
        <init-param>  
        <!-- 指定org.springframework.orm.jpa.LocalEntityManagerFactoryBean在spring配置檔案中的名稱,預設值為entityManagerFactory   
        如果LocalEntityManagerFactoryBean在spring中的名稱不是entityManagerFactory,該參數一定要指定,否則會出現找不到entityManagerFactory的例外 -->  
            <param-name>entityManagerFactoryBeanName</param-name>  
            <param-value>entityManagerFactory</param-value>  
        </init-param>    
    </filter>  
    <filter-mapping>  
        <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>  

<filter>
        <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
        <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
        <init-param>
        <!-- 指定org.springframework.orm.jpa.LocalEntityManagerFactoryBean在spring配置檔案中的名稱,預設值為entityManagerFactory
        如果LocalEntityManagerFactoryBean在spring中的名稱不是entityManagerFactory,該參數一定要指定,否則會出現找不到entityManagerFactory的例外 -->
            <param-name>entityManagerFactoryBeanName</param-name>
            <param-value>entityManagerFactory</param-value>
        </init-param> 
    </filter>
    <filter-mapping>
        <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>