2010-12-05 89 views
1

我知道這個問題已經在這裏提出幾次了。然而,我找不到任何解決方案,因此我決定再次發佈。延遲加載錯誤

我使用的是Spring MVC框架Hibernate和我想取我問心無愧類子類:

public class Scene implements Serializable{ 
private Long id; 
private Author author; 
//omitting getters and setters 
} 

public class Author{ 
private Long id; 
Private String name; 
//omitting getters and setters 
} 

我的Hibernate配置如下:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 
    <property name="driverClassName" value="org.postgresql.Driver" /> 
    <property name="url" value="jdbc:postgresql://127.0.0.1/doolloop2" /> 
    <property name="username" value="doolloop2" /> 
    <property name="password" value="doolloop" /> 
</bean> 
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
    <property name="dataSource" ref="dataSource" /> 
    <property name="mappingLocations"> 
     <list> 
     <value>WEB-INF/mapping/Scene.hbm.xml</value> 
     <value>WEB-INF/mapping/Author.hbm.xml</value> 
     </list> 
    </property> 
    <property name="hibernateProperties"> 
<props> 
    <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop> 
    <prop key="hibernate.show_sql">true</prop> 
    <prop key="hibernate.hbm2ddl.auto">update</prop> 
    <prop key="hibernate.cache.use_second_level_cache">true</prop> 
    <prop key="hibernate.cache.use_query_cache">true</prop> 
    <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> 
    </props> 
    </property> 
</bean> 
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="sessionFactory" /> 
</bean> 

<bean id="txService" class="com.doolloop.services.TxDataBaseServiceImpl"> 
     <property name="sessionFactory"> 
     <ref local="sessionFactory"/> 
     </property> 
    </bean> 

現在我有方法得到我的場景:

@Override 
    @Transactional(readOnly = true) 
    public Scene getScene(Long id) { 
     Session session = this.sessionFactory.getCurrentSession(); 
     Query q = session.createQuery("select scene from com.doolloop.objects.Scene scene where scene.id=:id"); 
     q.setLong("id", id); 
     Scene scene = (Scene)q.uniqueResult() 
     return scene; 

    } 

and my spring mvc code:

@RequestMapping(value="/getSceneMetaData.dlp",method = RequestMethod.GET) 
    @ResponseBody 
    public Scene getSceneMetaData(@RequestParam String id){ 
     Scene scene = service.getScene(Long.parseLong(id)); 
     return scene; 
    } 

當我執行它,我得到了followng例外:

Dec 5, 2010 12:29:21 PM org.hibernate.LazyInitializationException <init> 
    SEVERE: failed to lazily initialize a collection of role: com.doolloop.objects.Scene.author, no session or session was closed 
    org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.doolloop.objects.Scene.vauthor, no session or session was closed 

我GOOGLE了它,瞭解它是因爲它試圖獲取作者在交易關閉和作者類是由懶人默認,但我不明白的是我應該如何修改我的代碼,以便解決它。

任何建議更受歡迎。

UPD:這裏是兩個類的映射文件:

<class 
     name="com.doolloop.objects.Scene" 
     table="scene" 
    > 
     <id 
      name="id" 
      column="Id" 
      type="java.lang.Long" 
      unsaved-value="null" 
     > 
     <generator class="sequence"> 
       <param name="sequence">doolloop2.sceneseq</param> 
      </generator> 
     </id> 
    <many-to-one 
     name="author" 
     class="com.doolloop.objects.Author" 
     cascade="all" 
     column="authorid" 
     unique="false" 
    /> 
    </class> 

<hibernate-mapping> 
    <class 
     name="com.doolloop.objects.Author" 
     table="authors" 
    > 
     <id 
      name="id" 
      column="Id" 
      type="java.lang.Long" 
      unsaved-value="null" 
     > 
     <generator class="sequence"> 
       <param name="sequence">doolloop2.authorseq</param> 
      </generator> 
     </id> 
     <property 
      name="name" 
      update="true" 
      insert="true" 
      not-null="false" 
      unique="false" 
      type="java.lang.String" 
     > 
      <column name="name" /> 
     </property> 
      <property 
      name="email" 
      update="true" 
      insert="true" 
      not-null="false" 
      unique="false" 
      type="java.lang.String" 
     > 
      <column name="email" /> 
     </property> 
     <property 
      name="site" 
      update="true" 
      insert="true" 
      not-null="false" 
      unique="false" 
      type="java.lang.String" 
     > 
      <column name="site" /> 
     </property> 
     <property 
      name="contactInfo" 
      update="true" 
      insert="true" 
      not-null="false" 
      unique="false" 
      type="java.lang.String" 
     > 
      <column name="contactInfo" /> 
     </property> 
    </class> 

UPD2我增加了以下我的web.xml:

<listener> 
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener> 
<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value>WEB-INF/applicationContext.xml</param-value> 
</context-param> 
    <filter> 
    <filter-name>openSessionInViewFilter</filter-name> 
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>openSessionInViewFilter</filter-name> 
    <url-pattern>/getSceneMetaData.dlp</url-pattern> 
</filter-mapping> 

它給了我以下異常:

org.codehaus.jackson.map.JsonMappingException: could not initialize proxy - no Session (through reference chain: com.doolloop.objects.Scene["author"]->com.doolloop.objects.Author_$$_javassist_4["name"]) 

Update3:

這是該操作的log4j輸出:

2010-12-06 11:48:09,031 DEBUG [org.springframework.orm.hibernate3.support.OpenSessionInViewFilter] - Using SessionFactory 'sessionFactory' for OpenSessionInViewFilter 
2010-12-06 11:48:09,036 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean 'sessionFactory' 
2010-12-06 11:48:09,040 DEBUG [org.springframework.orm.hibernate3.support.OpenSessionInViewFilter] - Opening single Hibernate Session in OpenSessionInViewFilter 
2010-12-06 11:48:09,042 DEBUG [org.springframework.orm.hibernate3.SessionFactoryUtils] - Opening Hibernate Session 
2010-12-06 11:48:09,048 DEBUG [org.springframework.web.servlet.DispatcherServlet] - DispatcherServlet with name 'doolloop' processing GET request for [/dlp/getSceneMetaData.dlp] 
2010-12-06 11:48:09,056 DEBUG [org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping] - Mapping [/getSceneMetaData.dlp] to HandlerExecutionChain with handler [[email protected]] and 2 interceptors 
2010-12-06 11:48:09,060 DEBUG [org.springframework.web.servlet.DispatcherServlet] - Last-Modified value for [/dlp/getSceneMetaData.dlp] is: -1 
2010-12-06 11:48:09,142 DEBUG [org.springframework.core.convert.support.GenericConversionService] - Converting value '140' of [TypeDescriptor java.lang.String] to [TypeDescriptor @org.springframework.web.bind.annotation.RequestParam java.lang.String] 
2010-12-06 11:48:09,146 DEBUG [org.springframework.core.convert.support.GenericConversionService] - Converted to '140' 
2010-12-06 11:48:09,148 DEBUG [org.springframework.web.bind.annotation.support.HandlerMethodInvoker] - Invoking request handler method: public com.doolloop.objects.Scene com.doolloop.controllers.SceneController.getSceneMetaData(java.lang.String) 
2010-12-06 11:48:16,401 DEBUG [org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver] - Resolving exception from handler [[email protected]]: org.codehaus.jackson.map.JsonMappingException: could not initialize proxy - no Session (through reference chain: com.doolloop.objects.Scene["author"]->com.doolloop.objects.Author_$$_javassist_4["name"]) 
2010-12-06 11:48:16,561 DEBUG [org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver] - Resolving exception from handler [[email protected]]: org.codehaus.jackson.map.JsonMappingException: could not initialize proxy - no Session (through reference chain: com.doolloop.objects.Scene["author"]->com.doolloop.objects.Author_$$_javassist_4["name"]) 
2010-12-06 11:48:16,568 DEBUG [org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver] - Resolving exception from handler [[email protected]]: org.codehaus.jackson.map.JsonMappingException: could not initialize proxy - no Session (through reference chain: com.doolloop.objects.Scene["author"]->com.doolloop.objects.Author_$$_javassist_4["name"]) 
2010-12-06 11:48:16,572 DEBUG [org.springframework.web.servlet.DispatcherServlet] - Could not complete request 
org.codehaus.jackson.map.JsonMappingException: could not initialize proxy - no Session (through reference chain: com.doolloop.objects.Scene["author"]->com.doolloop.objects.Author_$$_javassist_4["name"]) 
    at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:215) 

//// Entire stack trace goes here. 

2010-12-06 11:48:16,660 DEBUG [org.springframework.orm.hibernate3.support.OpenSessionInViewFilter] - Closing single Hibernate Session in OpenSessionInViewFilter 
2010-12-06 11:48:16,662 DEBUG [org.springframework.orm.hibernate3.SessionFactoryUtils] - Closing Hibernate Session 

UPDATE4:

我看到的只有一個選擇不適用控制檯:

Hibernate: select scene0_.Id as Id20_0_, scene0_.name as name20_0_, scene0_.description as descript3_20_0_, scene0_.defaultView as defaultV4_20_0_, scene0_.authorid as authorid20_0_ from scene scene0_ where scene0_.Id=? 

但是如果我修改我的getScene方法如下:

public Scene getScene(Long id) { 
     Session session = this.sessionFactory.getCurrentSession(); 
     Query q = session.createQuery("select scene from com.doolloop.objects.Scene scene where scene.id=:id"); 
     q.setLong("id", id); 
     Scene scene = (Scene)q.uniqueResult() 
     **Author author = scene.getAuthor();** 
     return scene; 

我會看到第二個選擇出現:

Hibernate: select author0_.Id as Id23_0_, author0_.name as name23_0_, author0_.email as email23_0_, author0_.site as site23_0_, author0_.contactInfo as contactI5_23_0_ from authors author0_ where author0_.Id=? 

但筆者對象無線本地環路是靜靜空。

從控制器調用相同的getter會導致異常。

回答

7

這可能是值得首先發布Scene.hbm.xml和Author.hbm.xml ..

從我在這裏看到的: https://forum.hibernate.org/viewtopic.php?f=1&t=994772&start=0 多到一的關係在默認情況下即時加載,如果你使用註解,但是這不是如果你使用XML映射會發生什麼!

我會說修改多對一的關係,並明確設置fetch="EAGER"

所以結果應該是:

<many-to-one 
    name="author" 
    class="com.doolloop.objects.Author" 
    cascade="all" 
    column="authorid" 
    unique="false" 
    fetch="EAGER" 
/> 

你提到,你有2個使用場景:一個在那裏你獲取場景的對象,你需要它的依賴性和一個在那裏你只關心id和它的幾個字段。這似乎是定義Hibernate會話邊界的問題。您可以使用這裏描述的SessionInViewFilter:http://community.jboss.org/wiki/OpenSessioninView這樣,Hibernate會話將在http請求期間打開,因此您將能夠訪問延遲加載的引用,以呈現時間。這有幫助嗎?

=================================
我見過你的OpenSessionInViewFilter定義 - 它可能是值得的明確設置你的HibernateSessionFactory名稱:

<filter> 
    <filter-name>openSessionInViewFilter</filter-name> 
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> 
    <init-param> 
     <param-name>sessionFactoryBeanName</param-name> 
     <param-value>sessionFactory</param-value> 
    </init-param> 
</filter> 

另外,我沒有看到你的Tx經理的正確初始化在Spring配置。只是定義它是不夠的,你需要:

<tx:annotation-driven transaction-manager="transactionManager"/> 

=================================
從我在Hibernate文檔中看到的情況來看,很可能一旦關閉事務,Hibernate會話就會結束(即使您使用OpenSessionInView過濾器)。 看一看這裏: http://community.jboss.org/wiki/OpenSessioninView#Can_I_commit_the_transaction_before_rendering_the_view

一旦你關閉你的事務,數據庫連接返回到池中,並在數據庫中的所有進一步的訪問將需要一個新的連接,它應該有自動提交模式下。

然而,在你的情況下,我認爲解決方案是確保你已經加載了所有你需要從數據庫加載,而交易仍然是開放的!

+0

完成,但我不認爲問題在那裏,問題在我處理交易的方式,但無論如何,謝謝你提前。 – 2010-12-05 13:53:29