休眠/春季:getHibernateTemplate().save(...) 冻结/挂起

Posted

技术标签:

【中文标题】休眠/春季:getHibernateTemplate().save(...) 冻结/挂起【英文标题】:Hibernate/Spring: getHibernateTemplate().save(...) Freezes/Hangs 【发布时间】:2011-06-05 20:03:13 【问题描述】:

我将 Hibernate 和 Spring 与 DAO 模式一起使用(*DAO.java 类中的所有 Hibernate 依赖项)。我有九个单元测试(JUnit),它们创建一些业务对象,保存它们,并对它们执行操作;对象在散列中(所以我一直在重用相同的对象)。

我的 JUnit 设置方法调用我的 DAO.deleteAllObjects() 方法,该方法为我的业务对象表调用 getSession().createSQLQuery("DELETE FROM <tablename>").executeUpdate()(只有一个)。

我的一个单元测试 (#8/9) 冻结。我认为这是数据库死锁,因为 Hibernate 日志文件最后显示了我的删除语句。然而,调试表明它只是 HibernateTemplate.save(someObject) 冻结。 (Eclipse 显示它在 HibernateTemplate.save(Object),第 694 行处冻结。)

另外值得注意的是,单独运行此测试(不在 9 个测试套件中)不会导致任何问题。

究竟该如何解决和解决这个问题?

另外,我正在使用 @Entity 注释,如果这很重要的话。

编辑:我删除了我的业务对象的重用(在每个方法中使用唯一的对象)——没有任何区别(仍然冻结)。

编辑:这也开始渗透到其他测试中(不能运行多个测试类而不会冻结)

编辑: 将冻结测试分为两个类是可行的。我现在打算这样做,可耻的是,让两个或多个测试类对同一个业务对象类进行单元测试是不干的。

交易配置:

    <bean id="txManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <tx:advice id="txAdvice" transaction-manager="txManager">
        <!-- the transactional semantics... -->
        <tx:attributes>
            <!-- all methods starting with 'get' are read-only -->
            <tx:method name="get*" read-only="true" />
            <tx:method name="find*" read-only="true" />
            <!-- other methods use the default transaction settings (see below) -->
            <tx:method name="*" />
        </tx:attributes>
    </tx:advice>

    <!-- my bean which is exhibiting the hanging behavior -->
    <aop:config>
    <aop:pointcut id="beanNameHere"
        expression="execution(* com.blah.blah.IMyDAO.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="beanNameHere" />
</aop:config>

【问题讨论】:

你是否在每个测试方法之后提交事务? 我是一个 hibernate n00b(对 NHibernate 更有经验——几乎不需要任何配置),所以我假设是的,我是。我已经编辑了我的答案以包含一些事务配置。我也尝试调用 session.flush() 和 transaction.flush(),但无济于事。 【参考方案1】:

当冻结发生时会中断应用程序,找到主线程并捕获堆栈跟踪。仔细检查,直到您确切地找到正在运行的数据库查询在数据库中阻塞。

您提到自己运行测试可以,但运行完整套件会导致问题。如果是这种情况,那么我猜前面的测试之一仍然有一个事务打开,并且在阻塞测试试图访问的某些行上锁定了。

您的测试是否同时运行?如果是这样,请停止这样做,因为它们可能会相互干扰。

打开 hibernate.show_sql 选项,这样您就可以在控制台中看到正在生成的所有 SQL。

在冻结发生时,您可以找出哪些行被锁定在数据库中。例如在 SQLServer 中,您可以运行 sp_lock 来查看此内容,运行 sp_who 来查看哪些 SQL 进程 ID 正在阻塞另一个。

【讨论】:

是的,我也怀疑交易。测试是线性运行的(不知道它们可以同时运行)。 hibernate.show_sql 已打开,它显示的最后一件事是 DELETE FROM SomeTable (来自成功完成的测试设置)。它没有显示下一个 Hibernate 查询的开始,INSERT INTO ...据我所知,mysql 中没有打开的事务。【参考方案2】:

需要检查的几件事:

正确的事务管理 - 在您的配置中,您似乎有通过您的 DAO 进行的事务。通常,建议在您的服务层而不是 DAO 周围进行事务。但无论如何 - 确保您有一个围绕测试使用的 dao 的事务。或者进行测试@Transactional(如果使用spring的junit runner)

将数据源的日志记录阈值更改为info(也许是c3p0?)。它报告死锁。

查看数据库日志中是否存在死锁(如果有这样的选项)

【讨论】:

检查了以上所有内容,但都没有解决我的问题。并且数据库没有显示任何死锁,这是可疑的。

以上是关于休眠/春季:getHibernateTemplate().save(...) 冻结/挂起的主要内容,如果未能解决你的问题,请参考以下文章

休眠/春季:getHibernateTemplate().save(...) 冻结/挂起

TransactionRequiredException:没有事务正在进行春季批处理作业和休眠

春季启动和休眠:更新条目为空的所有列的行

春季启动中的休眠统计信息不起作用?

休眠的动态类

春季安全删除用户 - 会话仍处于活动状态