Пытаться уничтожить бобы в правильном порядке с помощью Spring - PullRequest
6 голосов
/ 18 января 2010

У меня есть веб-приложение с Spring, настроенное для создания моей фабрики сеансов гибернации (singleton) и сеанса и транзакции (обе являются областью запроса), но оно разрушает сеанс и транзакцию в неправильном порядке. Как я могу настроить его так, чтобы транзакция была уничтожена перед сеансом? Вот мой весенний файл applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
      "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
  <bean id="hibernateSessionFactory" scope="singleton"
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="configLocation" value="classpath:hibernate.cfg.xml" />
  </bean>

  <!-- The per-http request hibernate session -->
  <bean id="hibernateSession" factory-bean="hibernateSessionFactory"
    factory-method="openSession" destroy-method="close" scope="request" />

  <!--  The per-http request transaction (i need this to be destroyed BEFORE the session) -->
  <bean id="hibernateTransaction" factory-bean="hibernateSession"
    factory-method="beginTransaction" destroy-method="commit" scope="request" />
</beans>

А вот журнал, который показывает, что он закрывает сессию до закрытия транзакции:

16111 [http-8080-3] DEBUG org.springframework.beans.factory.support.DisposableBeanAdapter  - Invoking destroy method 'close' on bean with name 'hibernateSession'
16111 [http-8080-3] DEBUG org.hibernate.jdbc.ConnectionManager  - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
16111 [http-8080-3] DEBUG com.mchange.v2.resourcepool.BasicResourcePool  - trace com.mchange.v2.resourcepool.BasicResourcePool@17e4dee [managed: 4, unused: 3, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@19a8416)
16111 [http-8080-3] DEBUG org.springframework.beans.factory.support.DisposableBeanAdapter  - Invoking destroy method 'commit' on bean with name 'hibernateTransaction'
16111 [http-8080-3] DEBUG org.hibernate.transaction.JDBCTransaction  - commit
16111 [http-8080-3] WARN  org.springframework.beans.factory.support.DisposableBeanAdapter  - Invocation of destroy method 'commit' failed on bean with name 'hibernateTransaction'
org.hibernate.SessionException: Session is closed

Ответы [ 3 ]

4 голосов
/ 18 января 2010

Кажется, что порядок вызова метода destory для bean-объектов не-синглтонной области полностью вышел из-под контроля. Из документов ( 5.1.4 Использование зависит от ):

Атрибут зависимый в определении компонента может указывать как время инициализации Зависимость и, только в случае синглтон-компонентов , соответствующее время уничтожения зависимость

Вы можете создать вспомогательный объект и поручить ему создание и уничтожение ваших bean-компонентов:

public class HelperObject
{
    private SessionFactory factory;
    private Session session;
    private Transaction tx;

    public void init()
    {
        session = factory.createSession();
        tx = session.beginTransaction();
    }

    public void destroy()
    {
        tx.commit();
        session.close();
    }

    ...
} 

-

<bean id = "helperObject" class = "HelperObject" scope = "request" init-method = "init" destroy-method = "destroy">
    <property name = "factory" ref = "hibernateSessionFactory" />
</bean>

<bean id="hibernateSession" factory-bean="helperObject" 
    factory-method="getSession" scope="request" /> 

<bean id="hibernateTransaction" factory-bean="helperObject" 
    factory-method="getTransaction" scope="request" />

И, в конце концов, возможно, это не лучший способ управления сеансами и транзакциями Hibernate в Spring. Рассмотрите возможность использования встроенной поддержки Spring Hibernate и .

EDIT: Ну, правильный способ управления транзакциями это :

  • Вам не нужны параметры запроса session и transaction бобов
  • Вы не должны вызывать createSession на фабрике сеансов, возвращенной org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean. Вы можете добавить эту фабрику сессий в свои bean-компоненты и вызывать getCurrentSession, когда вам нужен сеанс, a он будет работать нормально.
  • Вы можете использовать декларативное управление транзакциями (@Transactional аннотации для транзакционных методов). Чтобы это работало, вы должны добавить в свой конфиг:

.

<bean id="transactionManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="hibernateSessionFactory"/>
</bean>

<tx:annotation-driven/>
  • Для получения дополнительной информации см. Ссылки выше
1 голос
/ 18 января 2010

Транзакции должны быть связаны со службами, если вы следуете идиоме Spring.Сессии - это объекты веб-уровня, полностью отделенные от уровня обслуживания.Мне кажется, что вы ошиблись, перепутав свой веб-уровень с сервисным уровнем.Лучше дразнить их врозь;у вас вряд ли возникнет такая проблема с этим соглашением.

1 голос
/ 18 января 2010

Вы можете заявить, что hibernateTransaction зависит от hibernateSession. Поскольку контейнер будет создавать экземпляры bean-компонентов в порядке зависимостей (за исключением циклических зависимостей) и разбирать их в обратном порядке, это должно сработать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...