2011-08-02 94 views
5

我遇到了一個奇怪的情況,在我的一個控制器上發生延遲加載問題。 注意:我正在使用OpenSessionInViewInterceptor,並將我的「服務」層註釋爲Transactional。Spring + Hibernate懶惰加載錯誤

我有幾種不同的方法來加載一個Person對象,一個是它的密鑰,另一個是它的SSN。在我的人物對象上,我收集了一些我懶洋洋地加載的角色。當我通過鍵加載時,我可以按照預期訪問列表。當我通過SSN加載時,我無法訪問列表。

在我的服務層配置文件我已經加入:

<tx:annotation-driven /> 

這裏是通過加載重點& SSN的人(我知道這需要在DAO /重組一個我的服務層片 - 這被繼承代碼) - 注意既不版本的SSN件允許裝載 - 無論是在同一個類:

@Transactional(readOnly = true, propagation = Propagation.REQUIRED) 
public Person loadPersonByKey(final Person.Key personKey) { 
    Assert.notNull(personKey); 
    return (Person) getHibernateTemplate().get(Person.class, personKey); 
} 

@Transactional(readOnly = true, propagation = Propagation.REQUIRED) 
public Person findPersonBySsn(final SocialSecurityNumber ssn) { 

    @SuppressWarnings("unchecked") 
    //List<Person> results = getHibernateTemplate().findByNamedParam("from core.model.entities.Person as person where ssn = :ssn", "ssn", ssn); 

    Criteria crit = getSession().createCriteria(Person.class); 
    crit.add(Restrictions.eq("ssn", ssn)); 
    List<Person> results = crit.list(); 

    int size = results.size(); 

    Person returnPerson = ((size != 0) ? (Person) results.get(0) : null); 
    return returnPerson; 
} 

唯一的區別在我的控制器是一個關鍵負載和一個負載的SSN。這裏是堆棧跟蹤的相關部分:

SEVERE: Servlet.service() for servlet springmvc threw exception 
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: core.model.entities.Person.memberships, no session or session was closed 
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383) 
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375) 
at org.hibernate.collection.AbstractPersistentCollection.readElementByIndex(AbstractPersistentCollection.java:176) 
at org.hibernate.collection.PersistentMap.get(PersistentMap.java:169) 
at core.model.entities.Person.getMemberships(Person.java:870) 
at core.springmvc.controllers.find.FindController.defaultAction(FindController.java:164) 

奇注意,如果我用SSN加載後立即加載關鍵的人,我能讀集合沒有問題。

編輯:

以下是前堆棧跟蹤日誌:

2011-08-02 13:29:32,415 [http-8080-1] DEBUG org.springframework.jdbc.datasource.DataSourceUtils CV#905cde28-e60c-4331 P#75004 - Resetting read-only flag of JDBC Connection [Transaction-aware proxy for target Connection [jdbc:oracle:thin:@(description=(address_list=(address=(host=127.0.0.1)(protocol=tcp)(port=11523))(load_balance=yes)(failover=yes))), UserName=USER_NAME, Oracle JDBC driver]] 
2011-08-02 13:29:32,415 [http-8080-1] DEBUG org.hibernate.impl.SessionImpl CV#905cde28-e60c-4331 P#75004 - disconnecting session 
2011-08-02 13:29:32,415 [http-8080-1] DEBUG org.hibernate.jdbc.ConnectionManager CV#905cde28-e60c-4331 P#75004 - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)] 
2011-08-02 13:29:32,415 [http-8080-1] DEBUG org.springframework.jdbc.datasource.DataSourceUtils CV#905cde28-e60c-4331 P#75004 - Returning JDBC Connection to DataSource 
2011-08-02 13:29:32,415 [http-8080-1] DEBUG org.hibernate.jdbc.ConnectionManager CV#905cde28-e60c-4331 P#75004 - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources! 
+0

此外,如果調用Hibernate.initialize(person),我仍然會得到初始化異常 - 即使我在服務層中這樣做。 – Scott

回答

2

你沒有表現出堆棧跟蹤的足以看出其中的例外是從哪裏來的,但我以爲這是在你的視圖層。這就是視圖模式中的開放會話。你說你正在使用OpenSessionInViewInterceptor,但顯然你沒有給它足夠的範圍。攔截器適用於方法調用。我猜測你已經將它應用於你的「服務」。如果是這樣,你可以把它關掉。它根本沒有爲你做任何事情。整個模式的要點是確保會話保持開放超出服務層邊界。對於典型的webapp,OpenSessionInViewFilter是合適的選擇。

+0

增加了兩行堆棧跟蹤。它絕對不是在視圖內部發生的。 – Scott

+0

@Scott:將組控制器變成「視圖」。你的OpenSessionInViewInterceptor應用在哪裏? –

+0

使用標準的OpenSessionInViewInterceptor。它適用於通過Dispatcher Servlet處理的所有請求。當我通過工作控制器和非工作控制器進行調試時,我發現攔截器正在使用一個會話。但是,一些東西必須配置錯誤,因爲休眠環繞在我懶散加載的集合中的持久集合在調試時沒有顯示會話。 – Scott