在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>