首先,我会注意到我使用 Spring + Hibernate 作为我的 JPA2 实现。我的应用程序配置了 JpaTransactionManager 和 HibernateJpaDialect。
我有一个停用一个单元的功能,我有一个包装停用多个单元的功能。单元停用工作调用外部服务,如果该调用超时或返回错误状态,它将抛出异常。如果单个单元停用失败(通过此外部服务调用或由于 RuntimeException),我只想回滚该单元的事务。
我可以使用 Propogation.REQUIRES_NEW 来实现这一点,基本上如下:
@Transactional
public void deactivateUnits(List<String> names){
for(String name : names){
deactivateUnit(name);
}
}
@Transactional(propogation=Propogation.REQUIRES_NEW, rollbackFor=MyException.class)
public void deactivateUnit(String name) throws MyException{
..snip..
//Some code that throws MyExceptions or RuntimeExceptions
..snip..
}
这非常有效。
这种风格也很好地扩展到激活。
@Transactional
public void activateUnits(List<String> names){
for(String name : names){
activateUnit(name);
}
}
@Transactional(propogation=Propogation.REQUIRES_NEW, rollbackFor=MyException.class)
public void activateUnit(String name) throws MyException{
..snip..
//Some code that throws MyExceptions or RuntimeExceptions
..snip..
}
然而,当我需要做的时候,我遇到了一个问题reactivation
。我想要的是一个reactivation
利用现有deactivateUnit
和activateUnit
函数的原子任务,这样如果或者deactivateUnit
或者activateUnit
导致回滚,则整个函数将回滚。
我对此的天真尝试不起作用:
@Transactional(propogation=Propogation.REQUIRES_NEW, rollbackFor=MyException.class)
public void reactivateUnit(String newName, String oldName) throws MyException{
deactivateUnit(oldName);
activateUnit(newName);
}
如果activateUnit
回滚,deactivateUnit
则不会。
我想也许我应该将激活和停用的传播更改为NESTED
,但这并不能保留函数的回滚行为。
我有点茫然,所以我很感激任何帮助!