一点背景:我正在使用Spring和Hibernate来创建一个非常简单的域/ dao /服务结构。我也在使用Autowiring将我所有的豆子注入他们喜欢的地方。
在重构时,我最近在尝试访问我的hibernate对象上的FetchType.LAZY属性时得到了一个非常流行的错误消息“无法初始化代理 - 无会话”。它是这样的:
public class Person {
...
@ManyToOne(cascade = {}, fetch = FetchType.LAZY)
@JoinColumn(name = "pet_id", nullable = false)
public Pet getPet() {
return pet;
}
...
}
我曾经有一个访问Pet属性的PersonService bean,并且没有遇到任何麻烦。但是,我最近重构了代码,以便PersonHelper查看它而不是查看Pet的PersonService。虽然我的帮助bean可以看到PersonDao,但是可以打电话来获取该人,但是当我的会话关闭时,它无法访问Pet。
所以,我认为我不清楚何时松开hibernate会话。所有的配置看起来都很好,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;
答案 0 :(得分:3)
在没有看到PersonService的代码/上下文配置的情况下,我只能猜测它在重构之前的工作原理。如果您使用HibernateInterceptor围绕DAO方法包装会话管理,则会在方法完成后立即关闭会话,除非事先打开(例如OpenSessionInViewFilter)。< / p>
我的猜测是HibernateInterceptor
的范围可能在重构期间发生了变化,因此会话现在在获取数据后立即关闭。您可能希望扩展HibernateInterceptor的范围以覆盖您的服务/业务方法,以便会话保持足够长的时间以便延迟提取工作,或者使用OpenSessionInViewFilter
来确保会话永远可用。
答案 1 :(得分:1)
OSIV始终是必须阅读的,无论您是否正在编写基于Web的应用程序。
我在Spring bean的方法(at the service layer)中使用@Transactional
标记,让Spring以这种方式为我管理会话(Spring默认处理每个线程的Hibernate会话)。