У меня есть веб-приложение с 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 ответа
Похоже, что порядок вызовов метода уничтожения для bean-компонентов без одноэлементной области полностью выходит из-под контроля. Из документов (5.1.4 Использование зависимости от):
Атрибут зависимости в определении bean-компонента может указывать как время инициализации, так и время инициализации. зависимости и, только в случае одноэлементных компонентов , соответствующее время уничтожения зависимость
Вы можете создать вспомогательный объект и делегировать ему создание и уничтожение ваших 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. и транзакции.
РЕДАКТИРОВАТЬ: Что ж, правильный способ управления транзакциями - это :
- Вам не нужны компоненты
session
иtransaction
с областью действия запроса - Вы не должны вызывать
createSession
в фабрике сеанса, возвращаемойorg.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean
. Вы можете внедрить эту фабрику сеансов в свои bean-компоненты и вызватьgetCurrentSession
, когда вам понадобится сеанс, и он будет работать нормально. - Вы можете использовать декларативное управление транзакциями (аннотации
@Transactional
к транзакционным методам). Чтобы он заработал, вам следует добавить в свой конфиг:
.
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="hibernateSessionFactory"/>
</bean>
<tx:annotation-driven/>
- Для получения дополнительной информации см. Ссылки выше
Вы можете заявить, что hibernateTransaction
зависит от hibernateSession
. Поскольку контейнер будет создавать экземпляры bean-компонентов в порядке зависимости (исключая циклические зависимости) и удалять их в обратном порядке зависимости, это должно помочь.
Транзакции должны быть связаны со службами, если вы следуете идиоме Spring. Сеансы - это объекты веб-уровня, полностью отделенные от уровня служб. Мне кажется, вы совершили ошибку, связав свой веб-уровень с уровнем услуг. Лучше разлучить их; у вас вряд ли возникнет проблема с такой договоренностью.
Похожие вопросы
Новые вопросы
java
Java - это язык программирования высокого уровня. Используйте этот тег, если у вас возникли проблемы с использованием или пониманием самого языка. Этот тег редко используется отдельно и чаще всего используется вместе с [spring], [spring-boot], [jakarta-ee], [android], [javafx], [hadoop], [gradle] и [maven].