[英]spring junit test with two hibernate transactions
我有 spring junit 测试,由两个作为 REQUIRES_NEW 传播的顺序事务组成:
public class ContractServiceTest extends AbstractIntegrationTest {
@Autowired
private PersistenceManagerHibernate persistenceManagerHibernate;
@Autowired
private ContractService contractService;
@Autowired
private EntityChangeService entityChangeService;
@Resource
private AddServiceService addService;
@Autowired
private ReferenceBookService refService;
@Autowired
private PropertyService propertyService;
@Autowired
private HibernateTransactionManager transactionManager;
@Test
public void testContractDeletes() {
Long contractId = 1L;
final Contract contract = createTestDetachedContract(contractId, PropertyServiceTest.createManaged(propertyService, refService), refService);
ensureContractCreated(contract);
deleteTransactional(contract);
Assert.assertEquals(1, entityChangeService.findByPaginationOrderByUpdateDate(Contract.class.getName(), contract.getId().toString(), null, 0, 30).size());
}
@Test
@Ignore
public void testContractCreates() {
Long contractId = 1L;
final Contract contract = createTestDetachedContract(contractId, PropertyServiceTest.createManaged(propertyService, refService), refService);
ensureContractDeleted(contract);
createContractTransactional(contract);
Assert.assertEquals(1, entityChangeService.findByPaginationOrderByUpdateDate(Contract.class.getName(), contract.getId().toString(), null, 0, 30).size());
}
private void ensureContractCreated(Contract contract) {
if (persistenceManagerHibernate.isCreated(Contract.class, contract.getId())) {
return;
}
createContractTransactional(contract);
}
private void deleteTransactional(final Contract contract) {
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.setPropagationBehavior(Propagation.REQUIRES_NEW.value());
transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
try {
contractService.delete(contract);
} catch (Exception e) {
toString();
}
return null;
}
});
}
private void createContractTransactional(final Contract contract) {
TransactionTemplate transactionTemplate2 = new TransactionTemplate(transactionManager);
transactionTemplate2.setPropagationBehavior(Propagation.REQUIRES_NEW.value());
transactionTemplate2.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
contractService.create(contract);
return null;
}
});
}
private void ensureContractDeleted(final Contract contract) {
if (!persistenceManagerHibernate.isCreated(Contract.class, contract.getId())) {
return;
}
deleteTransactional(contract);
}
public static Contract createTestDetachedContract(Long contractId, Property property, ReferenceBookService refService) {
Contract contract1 = new Contract();
contract1.setId(contractId);
contract1.setName("test name");
contract1.setProperty(property);
contract1.setNumber("10");
contract1.setType(refService.get(ContractType.class, 1L));
contract1.setStatus(refService.get(ContractStatus.class, 1L));
contract1.setCreated(new Date());
contract1.setCurrencyRate(new BigDecimal(10));
contract1.setInitialSum(new BigDecimal(10));
contract1.setSum(new BigDecimal(10));
return contract1;
}
}
测试在插入 sql 语句的事务提交时冻结,它是:
private void createContractTransactional(final Contract contract) {
TransactionTemplate transactionTemplate2 = new TransactionTemplate(transactionManager);
transactionTemplate2.setPropagationBehavior(Propagation.REQUIRES_NEW.value());
transactionTemplate2.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
contractService.create(contract);
return null;
}
});
}
为什么会发生这种情况(调试器在没有提供源代码的情况下停在某些 oracle 代码处)以及如何使用两个顺序事务正确编写 spring junit 测试?
听起来测试在数据库中的 Contract 表上造成了死锁。 其根本原因很可能是使用了REQUIRES_NEW
传播级别,如本问题中所述。 重要的部分是:
PROPAGATION_REQUIRES_NEW 为给定的 scope 启动一个新的、独立的“内部”事务。该事务将完全独立于外部事务提交或回滚,具有自己的隔离 scope、自己的一组锁等。外部事务将被挂起在内部的开始,并在内部完成后恢复
createContractTransactional
方法试图插入到 Contract 表中,但测试早期的某些东西必须锁定它,我猜这是对persistenceManagerHibernate.isCreated(Contract.class, contract.getId())
的调用。 无论是什么原因,您都有两个独立的事务锁定在同一个表上,即死锁。
尝试将测试中事务的传播级别设置为REQUIRED
,这是默认设置。 如果还没有,这将创建一个新事务,否则将使用当前事务。 那应该使您的测试在单个事务中执行,因此您不应该陷入僵局。 一旦它开始工作,您可能需要阅读spring 文档了解其传播级别,以确保REQUIRED
是满足您需要的正确级别。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.