hibernate 延遲加載的錯誤 failed to lazily initialize a collection of role
版權聲明:
原創作品,如需轉載,請與作者聯繫。否則將追究法律責任。
|
這個問題一般出現在一對多的情況下,解決的方法有兩種
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> |