Spring + Hibernate 懒加载错误

5
我遇到了一个奇怪的情况,在我的控制器中出现了懒加载问题。注意:我正在使用OpenSessionInViewInterceptor,并在我的“服务”层上注释了Transactional。 我有几种不同的方法来加载Person对象,一种是按其键加载,另一种是按其SSN加载。在我的person对象上,我有一个角色集合,需要懒加载。当我按键加载时,我能够像预期的那样访问列表。但是当我按SSN加载时,我无法访问该列表。
在我的服务层配置文件中,我已经添加了:
<tx:annotation-driven />

这是我的服务层代码,它通过关键字和社保号码加载人员信息(我知道这应该在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;
}

我的控制器唯一的区别是一个按Key加载,一个按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)

奇怪的是,如果我在通过社会安全号码加载人员之后立即按键加载,则可以毫无问题地读取集合。

编辑:

以下是堆栈跟踪之前的日志:

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!

即使在服务层调用 Hibernate.initialize(person),我仍然会收到初始化异常。 - Scott
1个回答

2
您没有展示足够的堆栈跟踪以查看异常来自哪里,但我假设它是在您的视图层中。这就是开放式会话视图模式的作用。您说您正在使用OpenSessionInViewInterceptor,但显然您没有给它足够广泛的范围。拦截器适用于方法调用。我猜想您已经将其应用于“服务”。如果是这样,那么您可能可以关闭它。它对您来说没有任何作用。该模式的整个重点是确保会话保持打开状态,超出了服务层边界。对于典型的Web应用程序,OpenSessionInViewFilter 是适当的选择。

添加了堆栈跟踪的下两行。它绝对不会发生在视图内部。 - Scott
@Scott:将控制器分组到“视图”中。你的OpenSessionInViewInterceptor应用在哪里? - Ryan Stewart
使用标准的OpenSessionInViewInterceptor。它适用于通过Dispatcher Servlet处理的所有请求。当我调试工作控制器和不工作的控制器时,我看到拦截器正在利用一个会话。但是,一些配置可能出错了,因为Hibernate包装我的延迟加载集合的持久集合在调试时没有显示任何会话。 - Scott
你不会有一些关闭或清除会话,或从会话中驱逐对象的代码吗? - Ryan Stewart
今天早上进来后我不得不再次确认。我没有看到任何显式调用驱逐、关闭、清除或类似操作的情况。 - Scott
我能从这里推荐的唯一事情就是要么发布一个SSCCE,要么在SessionImpl中输出“断开会话”行的断点上进行一些调试。如果那是你的会话,那么在尝试惰性加载某些内容之前,它不应该被断开连接。 - Ryan Stewart

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接