2010-07-18 3 views
4

Немного фона: Я использую Spring и Hibernate для создания действительно простой структуры домена/дао/сервиса. Я также использую Autowiring, чтобы вставлять все мои бобы в их счастливые места.Понимание SessionFactory весной

Во время рефакторинга у меня недавно появилось слишком популярное сообщение об ошибке «не удалось инициализировать прокси - нет сеанса» при попытке получить доступ к свойству FetchType.LAZY на моем спящем объекте. Это звучит примерно так:

public class Person { 

... 

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

Я использовал, чтобы иметь PersonService боб доступ к свойству Pet, и не было никаких проблем делать это. Тем не менее, я недавно реорганизовал код так, чтобы вместо PersonService, глядя на Pet, PersonHelper смотрит на него. Хотя мой вспомогательный компонент может видеть PersonDao, может позвонить, чтобы получить человека, он не может получить доступ к Pet, поскольку моя сессия закрыта.

Итак, я думаю, что неясно, когда я теряю сессию спящего режима. Все конфиги выглядят отлично, и DAO вводят в мой помощник, как будто он используется для ввода в мой сервис. Я не знаю, почему моя служба может заставить Пэт просто отлично, но мой помощник не может.

Любая помощь с пониманием этого «SessionFactory mystery» хорошо оценена. Я понимаю, что это может быть сложный вопрос, поэтому ссылки на некоторые хорошие материалы для чтения будут качать.

С тех пор я сменил код на FetchType.EAGER (работает отлично), но эта загадка сжигает целое в моем мозгу :).

Per запросов, здесь есть (упрощенно) смотреть в моей конфигурации:

<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 в помощнике:

@Autowired 
private PersonDao personDao; 

ответ

3

Не видя кода/контекста конфигурации для PersonService, я может только догадываться, почему он работал до рефакторинга. Если вы используете HibernateInterceptor для управления сеансом вокруг методов DAO, сеанс закрывается сразу же после завершения метода, если только он не был предварительно открыт (например, OpenSessionInViewFilter).

Мое предположение, что область HibernateInterceptor, возможно, изменилась во время рефакторинга, так что сеанс теперь закрывается сразу после получения данных. Вы можете взглянуть на расширение сферы действия HibernateInterceptor, чтобы покрыть ваши сервисные/бизнес-методы, чтобы сеанс поддерживался достаточно долго, чтобы ленивый выбор был выполнен, или, альтернативно, использовать OpenSessionInViewFilter, что гарантирует, что сеанс всегда доступен.

+0

Очень интересно. Я собираюсь изучить фильтры, так как это то, о чем я мало что знаю. – Stephano

+0

Добавлен в какую-то конфигурацию, которую я использую. AnnotationSessionFactoryBean может показаться немного странным, поскольку я пытаюсь упростить эту идею для этого сообщения (это на практике немного сложнее) – Stephano

+0

@Stephano - Спасибо за обновление. Думаю, ваш DAO реализован с использованием HibernateDaoSupport? Из деталей здесь я не вижу, как бы это сработало раньше. Возможно, вам просто повезло! (Или более реалистично, есть дополнительные подробности, которые могли бы устранить тайну.существует ли какое-либо управление транзакциями?) Возможно, ваши DAO вызывали другие DAO, и поэтому сеанс был открыт в течение всего первого вызова, который охватывает вложенные вызовы. Связано: http://stackoverflow.com/questions/2145024/lazy-loading-with-spring-hibernatedaosupport – mdma

1

OSIV всегда должен быть прочитан, если вы пишете веб-приложение или нет.

Я использую тег @Transactional в своих методах весенних бобах (at the service layer), и пусть Spring управляет сеансом для меня таким образом (весна обрабатывает сеанс Hibernate по потоку по умолчанию).

+0

+1 для сброса двух очень полезных ссылок – Stephano

Смежные вопросы