我正在使用带有DAO模式的Hibernate和Spring(* 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>
答案 0 :(得分:1)
当冻结发生时,破坏应用程序,找到主线程并捕获堆栈跟踪。直到找到正在运行的正在运行的数据库中阻塞的数据库查询。
你提到运行测试它自己的工作正常但运行完整套件会导致问题。如果是这种情况,那么我猜测其中一个先前的测试仍然打开了一个事务,并且在阻塞测试试图访问的某些行上有锁定。
您的测试是否同时运行?如果是这样就停止这样做,因为它们可能互相干扰。
启用hibernate.show_sql选项,以便在控制台中查看正在生成的所有SQL。
在冻结发生时,您可以找出DB中锁定的行。例如在SQLServer中,您可以运行sp_lock
来查看此内容,并sp_who
查看哪些SQL进程ID在另一个上阻止。
答案 1 :(得分:1)
要检查的一些事项:
正确的事务管理 - 在您的配置中,您可以通过DAO进行交易。通常,建议您在服务层周围进行交易,而不是DAO。但无论如何 - 确保测试使用的dao周围有一个事务。或者进行测试@Transactional
(如果使用spring的junit runner)
将数据源的日志记录阈值更改为info
(c3p0,也许?)。它报告了死锁。
观察数据库日志是否存在死锁(如果有这样的选项)