Hibernate spring注释会话未被关闭/刷新

时间:2012-01-31 00:19:56

标签: hibernate spring session annotations

我'继承'了一个使用Spring注释来管理Hibernate的事务/会话的项目。或者至少它意味着。目前,Hibernate会话永远不会被刷新(它们被设置为FLUSH_MODE_NEVER),并且需要手动刷新DAO以便将任何数据写入数据库。

此外,所有DTO对象都驻留在hibernate的内存中,最终导致OutOfMemory错误。

我相信我需要告诉Spring / Hibernate关闭会话或提交事务。在我的控制器类中,我有一个用于处理请求的带注释的方法:

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
    ...
    ...
}

在applicationContetxt.xml文件中我相信我设置了hibernate事务管理器并告诉spring使用注释:

<!-- hibernate3 transaction manager -->
<bean id="transactionManagerLocal" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="dataSource" ref="${local.data.source}" />
    <property name="sessionFactory" ref="localSessionFactory" />
</bean>

<!-- Demarcate using @Transactional annotation -->
<tx:annotation-driven transaction-manager="transactionManagerLocal" order="200" />

我不仅非常确定配置是错误的,因为如果不在每个DAO上手动调用flush,数据都不会被写入数据库,从日志文件中我们可以看到事务管理器已经刷新了会话结束已禁用:

INFO  [http-8080-2] TransactionFactoryFactory - Transaction strategy: org.springframework.orm.hibernate3.SpringTransactionFactory
INFO  [http-8080-2] TransactionManagerLookupFactory - No TransactionManagerLookup configured (in JTA environment, use of read-write or transactional second-level cache is not recommended)
INFO  [http-8080-2] SettingsFactory - Automatic flush during beforeCompletion(): disabled
INFO  [http-8080-2] SettingsFactory - Automatic session close at end of transaction: disabled

需要做些什么才能使Spring / hibernate自动刷新DAO和/或关闭会话以防止Hibernate使用大量内存?

欢呼声 丹

<!-- MySQL/InnoDB session factory -->
<bean id="localSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="${local.data.source}"/>
    <property name="mappingResources">
        <list>
            <value>net/company/projectname/domain/ExchangeRate.hbm.xml</value>
            <!-- Other  -->

        </list>
    </property>

   <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
            <prop key="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>
            <prop key="hibernate.connection.zeroDateTimeBehavior">convertToNull</prop>
            <!-- 
            DOES NOTHING
            <prop key="hibernate.transaction.flush_before_completion">true</prop>
            <prop key="hibernate.transaction.auto_close_session">true</prop>
            -->
        </props>
    </property>
</bean>

<!-- hibernate3 transaction manager -->
<bean id="transactionManagerLocal" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="dataSource" ref="${local.data.source}" />
    <property name="sessionFactory" ref="localSessionFactory" />
</bean>


<!-- Demarcate using @Transactional annotation -->
<tx:annotation-driven transaction-manager="transactionManagerLocal" order="200" />

<bean id="exchangeRateDAO" class="net.company.project.dao.hibernate.impl.ExchangeRateDAOImpl">
     <property name="sessionFactory" ref="localSessionFactory"/>
 </bean>     

4 个答案:

答案 0 :(得分:5)

我的一位聪明的同事发现了问题所在。

  

实际问题是你声明的方法   @Transactional是一个从基类调用的继承方法   class,这意味着Spring无法拦截调用   方法并将其包装在事务中。

     

Spring将事务管理作为方面和方面实现   用代理实现。这个的局限是如果一个对象   自己调用一个方法(这是因为这里发生的事情   继承)然后代理没有看到调用(因为它发生   在类内部,如调用私有方法),而不能   所以关于它的任何事情。

哪个有意义,但似乎非常危险,因为它无法在没有任何错误消息或警告的情况下写入任何数据。

答案 1 :(得分:2)

还有另一种方式,而不是hibernate模板(hibernate模板会将Spring耦合到hibernate,这就是它在Spring 3.1中被弃用的原因) 解决此问题的关键是删除除了dialct和url之外的所有hibernate配置 以简单的方式,从您的hibernate属性中删除事务性东西 因为你想要spring来管理事务,而不是休眠。 正如Marten Deinum在此网址中提到的http://forum.springsource.org/archive/index.php/t-47667.html 这是我的spring xml配置文件的片段

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="configLocation">    
        <value>
            classpath:/com/spring/hibernate.cfg.xml
        </value>
    </property>       
    </bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

这是hibernate文件

<session-factory> 
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="connection.driver_class">org.postgresql.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/test</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>

<mapping resource="com/spring/BloodType.hbm.xml" />
</session-factory>

不要忘记在您的方法或类中编写@Transactional 也用

Session session = sessionFactory.getCurrentSession();

和这个

BloodType b = new BloodType();
b.setId(new Long(1));
BloodType b1 = (BloodType)session.get(BloodType.class, 12L);
session.delete(b1);
session.save(b);

无需session.flush()transaction.commit()即可正常使用 希望它有效

答案 2 :(得分:1)

使用hibernate模板解决了它

@Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
       hibernateTemplate = new HibernateTemplate(sessionFactory);
}

然后使用此链接中的模板 http://singgihpraditya.wordpress.com/2010/02/13/spring-3-0-and-hibernate-tutorial-part-1/

你的回复很好分享

答案 3 :(得分:0)

如果事务(带注释)成功,则会自动调用transaction.commit()并将内容写入数据库,请检查是否正在调用事务并且不会抛出异常。

还要确保将sessionfactory链接到声明的transcation。