Hibernate/Spring:getHibernateTemplate().save(...) 出现卡顿/挂起问题

5
我正在使用Hibernate和Spring与DAO模式(所有Hibernate依赖项在*DAO.java类中)。我有九个单元测试(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>

你在每个测试方法后都提交事务了吗? - Bozho
我是一个Hibernate新手(对NHibernate更有经验——几乎不需要配置),所以我猜我是。我编辑了我的答案,包括一些事务配置。我还尝试调用session.flush()和transaction.flush(),但没有效果。 - ashes999
2个回答

1

当程序出现冻结时,中断应用程序,找到主线程并捕获堆栈跟踪。一直查找,直到找到在数据库中阻塞的确切DB查询。

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

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

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

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


是的,我也怀疑事务。测试是线性运行的(不知道它们可以并发运行)。hibernate.show_sql已开启,最后显示的是从测试设置中删除了SomeTable(成功完成)。它没有显示下一个Hibernate查询的开始,即INSERT INTO ...。就我所看到的,MySQL中没有打开的事务。 - ashes999

1

需要检查的几个事项:

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

  • 将数据源(例如 c3p0)的日志记录级别更改为 info。它会报告死锁。

  • 观察数据库日志以查找死锁(如果有此选项)


以上所有内容都已经检查过了,但是没有解决我的问题。数据库也没有显示任何死锁,这很可疑。 - ashes999

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接