Spring + Hibernate延迟加载错误

Sco*_*ott 5 java spring hibernate spring-mvc

我有一个奇怪的情况,我在我的一个控制器上遇到了延迟加载问题. 注意:我正在使用OpenSessionInViewInterceptor,并将我的"服务"层注释为Transactional.

我有几种不同的加载Person对象的方法,一种是通过它的键,另一种是通过它的SSN.在我的person对象上,我有一组角色,我懒得加载.当我按Key加载时,我能够按预期访问列表.当我通过SSN加载时,我无法访问该列表.

在我的服务层配置文件中,我添加了:

<tx:annotation-driven />
Run Code Online (Sandbox Code Playgroud)

这是我的服务层片段,它通过Key&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;
}
Run Code Online (Sandbox Code Playgroud)

我的控制器的唯一区别是一个按键加载,一个由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)
Run Code Online (Sandbox Code Playgroud)

奇怪的是,如果我在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!
Run Code Online (Sandbox Code Playgroud)

Rya*_*art 2

您没有显示足够的堆栈跟踪来查看异常来自何处,但我认为它位于您的视图层中。这就是视图模式中的开放会话的含义。您说您正在使用 OpenSessionInViewInterceptor,但显然您没有给它足够宽的范围。拦截器适用于方法调用。我猜你已经将它应用到你的“服务”中了。如果是这样,您最好将其关闭。它根本没有为你做任何事情。该模式的重点是确保会话在服务层边界之外保持开放。对于典型的 Web 应用程序,OpenSessionInViewFilter是合适的选择。