I've got a web app with Spring set up to create my hibernate session factory (singleton) and session and transaction (both are request scoped), but it is destroying the session and transaction in the wrong order. How can i configure it so that the transaction is destroyed before the session? Here's my spring applicationContext.xml file:
<?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>
And here's the log that shows it closing the session before it closes the transaction:
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
It seems to be that the order of destory method calls for non-singleton-scoped beans is completely out of control. From docs (5.1.4 Using depends-on):
The depends-on attribute in the bean definition can specify both an initialization time dependency and, in the case of singleton beans only, a corresponding destroy time dependency
You may create a helper object and delegate creation and destruction of your beans to it:
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" />
And, after all, perhaps it is not the best way to manage Hibernate sessions and transactions in Spring. Consider using of Spring's built-in Hibernate and transactions support.
EDIT: Well, the right way to manage transactions is:
session
and transaction
beanscreateSession
on the session factory returned by org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean
. You can inject this session factory into your beans and call getCurrentSession
when you need a session, a it will work fine.@Transactional
annotations on the transactional methods). To make it work you should add to your config:.
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="hibernateSessionFactory"/>
</bean>
<tx:annotation-driven/>
You could declare that hibernateTransaction
depends-on hibernateSession
. Since the container will instantiate beans in dependency order (barring cyclic dependencies), and tear them down in reverse dependency order, this should do the trick.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With