Trying to destroy beans in the correct order using Spring

I have a web application with Spring configured to create a hibernate factory (singleton) session, as well as a session and transaction (both are request fields), but this destroys the session and transaction in the wrong order, How can I configure it so that Was the transaction destroyed before the session? Here is 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 is the log that shows that it closes the session before closing 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] (eg 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 
+6
java spring hibernate struts2
source share
3 answers

It appears that the order in which the destory method is called for non-singleton bean objects is not completely controlled. From the documents ( 5.1.4 Using Dependence on ):

The dependency attribute in the component definition can indicate both the dependence of the initialization time, and, in the case of only single-element components , the corresponding dependence of the destruction time

You can create a helper object and instruct it to create and destroy your bean components:

 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 in the end, this may not be the best way to manage Spring Hibernate sessions and transactions. Consider using Spring Hibernate's built-in and transaction support.

EDIT: Well, the right way to manage transactions is:

  • You do not need binary session and transaction
  • You should not call createSession for the session factory returned by org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean . You can embed this session factory in your beans and call getCurrentSession when you need a session, it will work fine.
  • You can use declarative transaction management ( @Transactional annotations for transactional methods). For this to work, you must add to your config:

,

 <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="hibernateSessionFactory"/> </bean> <tx:annotation-driven/> 
  • See the links above for more information.
+4
source share

You can declare that hibernateTransaction dependent on hibernateSession . Since the container will instantiate beans in the dependency order (banning cyclic dependencies) and dump them in the reverse order, this should do the trick.

+1
source share

Transactions should be related to services if you follow the Spring idiom. Sessions are web tier objects that are completely separate from the service tier. It sounds like you made a mistake by messing up your web tier with a service tier. Better to tease them separately; you are unlikely to encounter this problem.

+1
source share

All Articles