Understanding the SessionFactory in Spring
A little background: I'm using Spring and Hibernate to create a really simple domain/dao/service structure. I'm also using Autowiring to inject all my beans into their happy places.
While refactoring, I recently got the all-too-popular error message "could not initialize proxy - no Session" when trying to access a FetchType.LAZY property on my hibernate object. It goes something like this:
public class Person {
...
@ManyToOne(cascade = {}, fetch = FetchType.LAZY)
@JoinColumn(name = "pet_id", nullable = false)
public Pet getPet() {
return pet;
}
...
}
I used to have a PersonService bean that accessed the Pet property, and had no trouble doing so. However, I recently refactored the code so that instead of the PersonService looking at the Pet, a PersonHelper looks at it. While my helper bean can see the PersonDao, can make a call to get the person, it cannot access the Pet as my session is closed.
So, I think that I'm unclear as to when I loose my hibernate session. All the configs look fine, and the DAO is getting injected into my helper, just like it used to get injected into my service. I'm not sure why my service could get the Pet just fine, but my helper cannot.
Any help with understand this "SessionFactory mystery" is well appreciated. I realize this might be a complicated subject, so links to some good reading material would rock.
I've since changed the code to FetchType.EAGER (working fine), but this riddle is burning a whole in my brain :).
Per requests, here is a (simplified) look into my config:
<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 开发者_StackOverflow社区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 is autowired into the helper:
@Autowired
private PersonDao personDao;
Without seeing the code/context config for PersonService, I can only guess as to why it worked before the refactoring. If you're using a HibernateInterceptor to wrap session management around your DAO methods, then the session is closed immediately after the method has finished, unless it was opened beforehand (such as by a OpenSessionInViewFilter).
My guess is that the scope of the HibernateInterceptor
may have changed during refactoring so that the session is now closed immediately after the data is fetched. You may want to look at extending the scope of HibernateInterceptor to cover your service/business methods, so that the session is kept around long enough for lazy fetching to work, or, alternatively, use the OpenSessionInViewFilter
, which ensures the session is always available.
OSIV is always a must-read be it you are writing a web-based application or not.
I use the @Transactional
tag in my Spring beans' methods (at the service layer) and let Spring to manage the session for me that way (Spring handles Hibernate's session per thread by default).
精彩评论