【问题标题】:Hibernate spring annotation sessions not being closed/flushed休眠弹簧注释会话未关闭/刷新
【发布时间】:2012-01-31 00:19:55
【问题描述】:

我“继承”了一个项目,该项目使用 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 文件中,我相信我设置了休眠事务管理器并告诉 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 上的刷新的情况下数据不会写入数据库,从日志文件中我们可以看到事务管理器正在刷新并且会话关闭禁用:

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>     

【问题讨论】:

  • 顺便说一句,我尝试将 truetrue 添加到配置文件。虽然它现在说启用了自动刷新和会话关闭,但如果不手动刷新 DAO,仍然没有数据写入数据库。

标签: hibernate spring session annotations


【解决方案1】:

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

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

Spring 将事务管理实现为切面,切面是 用代理实现。这样做的限制是,如果一个对象 对自身调用一个方法(这就是这里发生的事情,因为 继承)然后代理看不到调用(因为它发生了 在类内部,例如调用私有方法),并且不能 所以关于它的任何事情。

这是有道理的,但似乎非常危险,因为它无法写入任何数据而没有任何错误消息或警告。

【讨论】:

  • 你最后是怎么解决的?通过删除@Transactional 注释?
  • 我将带有@Transactional 注释的方法移到了另一个类。因为它现在在不同的类中,所以 Spring 代理任何类的方式也有效。当它与调用它的代码在同一个类中时,代理类被忽略,因为它们不适用于内部调用的方法。呃,如果这没有意义,我可能需要画一个图表来解释。
  • 接口也是这种情况还是只涉及从超类继承的方法?
  • @haki 它应该只在“this”上调用该方法时出现。
【解决方案2】:

还有另一种方法来代替休眠模板(休眠模板会将弹簧耦合到休眠,这就是它在 Spring 3.1 中被弃用的原因) 解决此问题的关键是删除除方言和 url 之外的任何休眠配置 以简单的方式,从您的休眠属性中删除事务性内容 因为您希望 spring 管理事务,而不是休眠。 正如此网址中提到的 Marten Deinum http://forum.springsource.org/archive/index.php/t-47667.html 这是我的spring xml配置文件的sn-p

<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"/>

这里是休眠文件

<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() 就可以正常工作 希望有效

【讨论】:

  • 嗨 Ali,问题是 Spring 没有选择 @Transactional 注释,因为它定义的函数是从同一个类调用的,所以 Spring 无法代理该函数打电话。
【解决方案3】:

使用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/

您的回复会很高兴分享

【讨论】:

  • 嗨,阿里,很遗憾,您无法再访问要测试的代码,但我认为您的建议并不能真正解决问题。
  • 嗨,阿里,很遗憾,您无法再访问要测试的代码,但我认为您的建议并不能真正解决实际问题。我需要事务在它们定义的地方工作(即围绕句柄请求函数)。将事务移到 DAO 内将完全改变回滚行为。
【解决方案4】:

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

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

【讨论】:

  • 没有例外,但我在日志中看不到有关正在提交的事务的任何内容。我能看到的关于会话的唯一信息是:INFO [http-8080-1] SessionFactoryImpl - 构建会话工厂 INFO [http-8080-1] SessionFactoryObjectFactory - 没有将工厂绑定到 JNDI,没有配置 JNDI 名称
  • 尝试在调试模式下运行应用程序,看看是否有任何提交的事务条目。
  • 我什么也没得到...添加 logger.info("事务是否处于活动状态" + TransactionSynchronizationManager.isActualTransactionActive());到请求方法的开头表明没有事务处于活动状态。
  • 这意味着事务 AOP 建议尚未开始.. 尝试使用 xml 进行配置(这是我擅长的)` `
  • 完成了,那 - 似乎没有做任何事情。调试 [http-8080-6] NameMatchTransactionAttributeSource - 添加事务方法 [*] 与属性 [PROPAGATION_REQUIRED,ISOLATION_DEFAULT]
猜你喜欢
  • 1970-01-01
  • 2016-11-04
  • 2012-03-10
  • 2020-03-13
  • 1970-01-01
  • 2011-01-23
  • 1970-01-01
  • 2010-10-28
  • 1970-01-01
相关资源
最近更新 更多