有人可以解释为什么第一个单元测试类有效,而第二个测试类失败并出现锁定等待超时错误?
第一个测试类:
public class Test1 extends AbstractTransactionalJUnit4SpringContextTests {
@Before
public void setUp() {
// do stuff through hibernate to populate database with test data
}
@Test
@Transactional(propagation = Propagation.NEVER)
public void testDeleteObject() {
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
// execute sql that deletes data populated in setUp() [i.e. this will require locks on the objects].
}
});
}
}
第二个测试类[获取锁定等待超时错误]:
public class Test2 extends AbstractTransactionalJUnit4SpringContextTests {
@Before
public void setUp() {
// do stuff through hibernate to populate database with test data
}
@Test
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void testObject() {
// execute sql that deletes data populated in setUp() [i.e. this will require locks on the objects].
}
}
我理解第二个测试类失败是因为两个事务正在为同一个锁争用,但由于它的in_progress事务状态,它们都不能放弃锁。我很困惑的是为什么第一个测试类成功执行sql。我可能理解这个错误,但是当transactionTemplate执行事务回调时,是否也没有创建新事务?在那种情况下,不应该发生同样的事情(锁定等待超时)?
答案 0 :(得分:1)
仅当有两个或更多连接访问相同数据时才会发生死锁。如果使用传播NEVER
注释的测试用例,您只有一个事务,一个由TransactionTemplate
创建。
第二种情况对我来说有点模糊。异常意味着有两个并发连接/事务 - 一个用于setUp
,另一个用于testObject
。传播REQUIRES_NEW
确实强制执行另一个连接,即使检测到一个连接,但我希望在此事务中也可以启动setUp
。您可以尝试在@Transactional
上删除testObject
。 AbstractTransactionalJUnit4SpringContextTests
使用@Transactional
进行注释,默认传播为REQUIRED
我相信。
答案 1 :(得分:1)
默认情况下,TransactionTemplate不会创建新事务。默认传播行为是PROPAGATION_REQUIRED。在第一种情况下,没有锁定问题,因为设置和删除是在同一事务中完成的。
您可以通过为类org.springframework.orm.jpa.JpaTransactionManager(甚至整个org.springframework包)将日志级别设置为DEBUG来查看何时创建新事务或重用现有事务。