2010-07-18 102 views
4

小背景:我使用Spring和Hibernate来创建一个非常简单的域/ dao /服务结构。我还使用Autowiring将所有的豆类注入到他们的开心地点。了解Spring中的SessionFactory

在重构时,最近我尝试访问我的hibernate对象上的FetchType.LAZY属性时,最近出现了一个非常流行的错误消息“无法初始化代理 - 没有会话”。它是这样的:

public class Person { 

... 

@ManyToOne(cascade = {}, fetch = FetchType.LAZY) 
@JoinColumn(name = "pet_id", nullable = false) 
public Pet getPet() { 
    return pet; 
} 
... 
} 

我曾经有一个PersonService bean访问Pet属性,并没有这样做的麻烦。不过,我最近重构了代码,以便PersonH​​elper不用查看Pet,而是PersonH​​elper查看它。虽然我的帮手bean可以看到PersonDao,但可以拨打电话获取此人,但由于我的会话已关闭,因此无法访问Pet。

所以,我认为我不清楚自己何时休眠会话。所有的配置看起来都很好,而且DAO被注入到我的帮助程序中,就像它用于注入我的服务一样。我不知道为什么我的服务可以让宠物得到好处,但我的帮手不能。

任何帮助理解这个“SessionFactory的奥秘”,非常感谢。我意识到这可能是一个复杂的主题,所以链接到一些好的阅读材料会摇摆。

我已经将代码更改为FetchType.EAGER(正常工作),但是这个谜语在我的大脑中燃烧了整个:)。

每请求,这里是一个(简化)看看我的配置:

<bean id="personSvc" class="org.comp.service.impl.PersonServiceImpl" /> 
    <bean id="personHelper" class="org.comp.service.helper.PersonHelper" /> 

    <bean id="personDao" class="org.comp.dao.hibernate.HibPersonDaoImpl"> 
     <property name="sessionFactory"> 
      <ref bean="sessionFactory" /> 
     </property> 
    </bean> 

... 

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 
     destroy-method="close"> 
    </bean> 

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
     <property name="dataSource"> 
      <ref bean="dataSource" /> 
     </property> 
     <property name="packagesToScan" value="org.comp.domain"/> 
     <property name="schemaUpdate" value="true" /> 
     <property name="hibernateProperties"> 
      <props> 
       <prop key="hibernate.show_sql">false</prop> 

       <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider 
       </prop> 
       <prop key="hibernate.cache.provider_configuration_file_resource_path">/hibernate-ehcache.xml</prop> 
      </props> 
     </property> 
    </bean> 
<bean id="transactionManager" 
    class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
    <property name="sessionFactory"> 
     <ref bean="sessionFactory"/> 
    </property> 
</bean> 

DAO被自动连接到帮助:

@Autowired 
private PersonDao personDao; 

回答

3

在没有看到代码/上下文配置为PersonService,我只能猜测为什么它在重构之前工作。如果您正在使用HibernateInterceptor来包装DAO方法的会话管理,那么会话在方法结束后立即关闭,除非事先打开(例如通过OpenSessionInViewFilter)。

我的猜测是HibernateInterceptor的范围可能在重构过程中发生了变化,因此会在获取数据后立即关闭会话。您可能需要考虑扩展HibernateInterceptor的范围以涵盖您的服务/业务方法,以便会话保持足够长的时间以便懒惰读取工作,或者使用OpenSessionInViewFilter,这可确保会话始终可用。

+0

非常有趣。我将研究过滤器,因为这是我不太了解的东西。 – Stephano 2010-07-18 18:56:19

+0

在我正在使用的某个配置中添加。 AnnotationSessionFactoryBean可能看起来有点奇怪,因为我试图简化这篇文章的想法(实际上它有点复杂) – Stephano 2010-07-18 19:03:00

+0

@Stephano - 感谢您的更新。我猜你的DAO是使用HibernateDaoSupport实现的?从这里的细节,我不知道它会如何工作。你可能只是很幸运! (或者更现实的是,还有更多的细节可以澄清这个谜团。是否有任何类型的事务管理?)可能是因为您的DAO正在调用其他DAO,因此会话在第一次调用期间保持打开状态,这会跨越嵌套的调用。相关:http://stackoverflow.com/questions/2145024/lazy-loading-with-spring-hibernatedaosupport – mdma 2010-07-18 19:20:39

1

OSIV永远是一个必须阅读的是,你正在写一个基于Web的应用程序或不。我在我的Spring beans的方法(at the service layer)中使用@Transactional标记,让Spring为我管理会话(Spring默认处理每个线程的Hibernate会话)。

+0

用于丢弃两个非常有用的链接 – Stephano 2010-07-18 19:46:21

相关问题