尝试使用Spring以正确的顺序销毁bean

Chr*_*ris 6 java spring hibernate struts2

我有一个使用Spring设置的Web应用程序来创建我的hibernate会话工厂(单例)和会话和事务(两者都是请求作用域),但它正在以错误的顺序销毁会话和事务.我如何配置它以便在会话之前销毁事务?这是我的spring 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>
Run Code Online (Sandbox Code Playgroud)

这是显示在关闭事务之前关闭会话的日志:

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
Run Code Online (Sandbox Code Playgroud)

axt*_*avt 5

似乎非单例范围 bean 的 destory 方法调用顺序完全失控。来自文档(5.1.4使用依赖):

bean 定义中的depends-on 属性可以指定初始化时间依赖性,以及(仅在单例 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();
    }

    ...
} 
Run Code Online (Sandbox Code Playgroud)

--

<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" />
Run Code Online (Sandbox Code Playgroud)

而且,毕竟,也许这不是在 Spring 中管理 Hibernate 会话和事务的最佳方式。考虑使用 Spring 的内置Hibernate事务支持。

编辑: 嗯,管理交易的正确方法

  • 您不需要请求范围sessiontransactionbean
  • 您不应该调用 .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/>
Run Code Online (Sandbox Code Playgroud)
  • 欲了解更多信息,请参阅上面的链接