休眠/春季: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(...) 冻结/挂起