给出这个示例代码:
public class MyServiceImpl implements MyService {
@Transactional
public void myTransactionalMethod() {
List<Item> itemList = itemService.findItems();
for (Item anItem : itemList) {
try {
processItem(anItem);
catch (Exception e) {
// dont rollback here
// rollback just one item
}
}
}
@Transactional
public void processItem(Item anItem) {
anItem.setSomething(new Something);
anItem.applyBehaviour();
itemService.save(anItem);
}
}
这是我想要实现的目标:
processItem(anItem);
才会回滚。myTransactionalMethod
应该继续,这意味着for-each应该结束。myTransactionalMethod
内发生异常但processItem(anItem)
不发生异常,则myTransactionalMethod
应完全回滚。 是否有解决方案不涉及手动管理交易(没有注释)?
编辑:我在考虑使用@Transactional(PROPAGATION=REQUIRES_NEW)
,但不知道它是否可以在同一个bean中运行。
答案 0 :(得分:7)
这是一种常见的误解。 Spring事务通过代理实现。代理是你班级的包装。您正在访问同一课程中的processItem
方法,即您没有通过代理,因此您无法获得任何交易。几年前I explained the mechanism in this answer。
解决方案:如果您需要嵌套事务,则需要两个单独的Spring bean,它们都必须由@Transactional
代理。
答案 1 :(得分:0)
看起来像NESTED交易的情况。 NESTED事务在具有保存点的外部事务中启动子事务,允许它回滚到该保存点。因为它是在外部转换结束时提交的嵌套事务。
public class MyServiceImpl implements MyService {
@Transactional
public void myTransactionalMethod() {
List<Item> itemList = itemService.findItems();
for (Item anItem : itemList) {
try {
// If you want to call this method directly configure your transaction use to aspectJ for transaction handling or refactor the code. Refer - [http://stackoverflow.com/questions/3423972/spring-transaction-method-call-by-the-method-within-the-same-class-does-not-wo][1]
processItem(anItem);
catch (Exception e) {
// dont rollback here
// rollback just one item
}
}
}
@Transactional(PROPAGATION = PROPAGATION.NESTED)
// Throw some runtime exception to rollback or some checkedException with rollbackFor attribute set in the above annotation
public void processItem(Item anItem) {
anItem.setSomething(new Something);
anItem.applyBehaviour();
itemService.save(anItem);
}
}
请注意,我还没有尝试过以下代码,看看是否有帮助。如果需要,您可能需要调整它。事实上,我很乐意在不久的将来尝试使用这些代码。