hibernate 延遲加載的錯誤 failed to lazily initialize a collection of role

hibernate 延遲加載的錯誤 failed to lazily initialize a collection of role


2009-05-13 14:27:04
 標籤:J2EE    [推送到技術圈 ]

版權聲明: 原創作品,如需轉載,請與作者聯繫。否則將追究法律責任。
這個問題一般出現在一對多的情況下,解決的方法有兩種
1、設置lazy=false
如果是用annotation,則配置如下
@OneToMany(
   targetEntity = CourseAuthorizationItem.class,
   cascade = {CascadeType.PERSIST, CascadeType.MERGE},
   mappedBy = "course", fetch=FetchType.EAGER
  )
將fetch類型設置成直接獲取

2、就是使用filter,過濾所有的鏈接
如果在使用filter的時候,要配置事務處理,否則會導致session處於只讀狀態而不能做修改、刪除的動作

< web-app >


< filter >
< filter-name > hibernateFilter </ filter-name >
< filter-class >
org.springframework.orm.hibernate.support.OpenSessionInViewFilter
</ filter-class >
</ filter >

< filter-mapping >
< filter-name > hibernateFilter </ filter-name >
< url-pattern > *.do </ url-pattern >
</ filter-mapping >

</ web-app >
 
 
 
 
failed to lazily initialize a collection of role: XXXXXX, no session or session was closed
例如:failed to lazily initialize a collection of role: com.gtc.wzgl.model.User.roles, no session or session was closed
這個異常大致意思是說在多對一的時候(並且lazy="false"),對象的實例失敗,多數出現的情況有
1、粗心造成
實例對象類名寫錯之類的
2、邏輯錯誤
如之前就已經傳遞過來一個實體對象,然後調用實體對象的方法時牽涉到1對多的情況,但此時SESSION已經關閉,所以根本無法進行一對多的操作。
3、設計到跨度的問題:
這樣打比方有多個實體對象,他們直接或則間接的有關聯。比如有4個實體,分別是廣告信息、廣告、廣告問答題、廣告商:他們之間的關係爲:
廣告商 1:n 廣告
廣告 1:n 廣告問答題
廣告商 1:n 廣告商信息
大家可以看到廣告和廣告商信息是沒有直接關係的。但我要添加廣告的時候我就必須將廣告商的實體做爲條件。那麼這麼一來廣告商信息可能間接的就必須用上。下面看我的操作:
ad(廣告),subject(題目)
     Ad ad = new Ad();
     ad.setAdProd(adform.getAdProd());
     ad.setIndustry(industry);
     ad.setAdPicture(pagefile.getFileName());
     ad.setAdFlack(adform.getAdFlack());
     ad.setAdDv(dvfile.getFileName());
     ad.setAdContent(adform.getAdContent());
     ad.setGray(gray);
     ad.setAdDate(new Date());
     ad.setOnlinetime(new Long(0));
     //以上爲廣告的基本信息填寫,而重要的是看下面一句,在這裏我的思路是subjectFormList是一個動態提交的表單,裏面有若干個廣告問答題。我將這些問答題變爲一個Set,然後作爲ad的一個屬性。
     Set<Subject> subjectset=getSubjectSet(subjectFormList,ad);
     ad.setSubjects(subjectset);
//然後提交,makePersistent是一個封裝的方法,用途就是save()啦。addao是一個DAO,裏面有ADUS。
addao.makePersistent(ad);
表面上看來很符合邏輯,只要我們在ad的映射裏面加上對subject的級聯更新就可以完成這項操作。但實際上會發生我們意想不到的問題,來讓我們看一下getSubjectSet()的內容:
public Set getSubjectSet(List<SubjectForm> subjectlist,Ad ad)
{
   Set<Subject> set=new HashSet<Subject>(0);
   Subject subject;
  
   for(Iterator<SubjectForm> it=subjectlist.iterator();it.hasNext();)
   {
    subject=new Subject();
    SubjectForm sf=it.next();
    subject.setSuContent(sf.getSucontent());
    subject.setSuOption(sf.getSuoption());
    subject.setSuResult(Arrays.deepToString(sf.getSuresult()));
    subject.setSuType(String.valueOf(sf.getSutype()));
    subject.setAd(ad);
    set.add(subject);
   }
  
  
   return set;
  
}
我們在這個方法上設一個斷點然後跟蹤,之後你會發現斷點在set.add(subject)只後就會出 failed to lazily initialize a collection of role: XXXXXXXX no session or session was closed這個異常,並且這個異常還是出在了廣告商的廣告信息上 gray.messages。是不是很不可理解?這也是Hibernate的懶漢機制問題。沒有任何一樣技術是完美的。那我們該怎麼處理這樣的問題。有很 多人以爲我們在廣告商對廣告商信息的隱射上加lazy="false"這樣在對gray操作會對messages進行關聯,並查詢時提出數據。但你會發現 改完之後會出現org.hibernate.LazyInitializationException: illegal access to loading collection這個異常。並切lazy="false"是我們不推薦的一種方法。他會降低你的查詢效率。
對於這樣的情況最好的解決辦法就是不要偷懶,對一個實體進行操作的時候就該用那個實體的DAO,即應該有2句HQL。如下把getSubjectSet()改一改:
public void getSubjectSet(List<SubjectForm> subjectlist,Ad ad)
{
   Set<Subject> set=new HashSet<Subject>(0);
   SubjectDAO subjectdao=DAOFactory.getDao(SubjectDAO.class);
  
  
   for(Iterator<SubjectForm> it=subjectlist.iterator();it.hasNext();)
   {
    Subject subject=new Subject();
    SubjectForm sf=it.next();
    subject.setSuContent(sf.getSucontent());
    subject.setSuOption(sf.getSuoption());
    subject.setSuResult(Arrays.deepToString(sf.getSuresult()));
    subject.setSuType(String.valueOf(sf.getSutype()));
    subject.setAd(ad);
    subjectdao.makePersistent(subject);
    //set.add(subject);
   }
  
}//遍歷出所有subject一個個的往數據庫里加。這樣便不會出問題了。
1、OpenSessionInView模式:
以下有2種方法,第1種是結合SPRING,第2種是採用了攔截器
Spring+Hibernate中,     集合映射如果使用lazy="true", 當PO傳到View層時, 出現未初始化session已關閉的錯誤,只能在dao先初始化
parent.getChilds().size();

Spring提供Open Session In View來解決這個問題, 有兩種方式
1. Interceptor
<!--</span><span style="COLOR: rgb(0,128,0)"> =========== OpenSession In View pattern ==============</span><span style="COLOR: rgb(0,128,0)">-->
    
< bean id ="openSessionInViewInterceptor"
             class
="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor" >
        
< property name ="sessionFactory" ref ="sessionFactory" />
    
</ bean >

    
< bean id ="urlMapping" class ="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" >
        
< property name ="interceptors" ref ="openSessionInViewInterceptor" />
        
< property name ="mappings" >
            
< props >
               ......
            
</ props >

        
</ property >
    
</ bean >
2. Filter
< web-app >

< filter >
< filter-name > hibernateFilter </ filter-name >
< filter-class >
org.springframework.orm.hibernate.support.OpenSessionInViewFilter
</ filter-class >
</ filter >

< filter-mapping >
< filter-name > hibernateFilter </ filter-name >
< url-pattern > *.do </ url-pattern >
</ filter-mapping >

</ web-app >
第2種解決方法:
Hibernate.initialize()強制加載關聯對象
 
今天又碰到錯誤
failed to lazily initialize a collection of role: no session or session was closed
試驗了一下發現了幾個解決方法:
1、是把對應一對多的那兩個列lazy=true改爲lazy=false即可
2、對於查詢中如果用的是xxx.load(class,id)則改爲xxx,get(class,id)
3在web.xml文件中加入
<filter>
   <filter-name>hibernateFilter</filter-name>
   <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
   <init-param>
            <param-name>singleSession</param-name>
            <param-value>false</param-value>
        </init-param>
<!--這個--   <init-param>一定要加不然很可能會報 錯:org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition
>
</filter>
<filter-mapping>
   <filter-name>hibernateFilter</filter-name>
   <url-pattern>*.mmg</url-pattern>
</filter-mapping>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章