2011-08-02 30 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