关键代码
关键类 RuleBasedTransactionAttribute
/**
* Winning rule is the shallowest rule (that is, the closest in the
* inheritance hierarchy to the exception). If no rule applies (-1),
* return false.
* @see TransactionAttribute#rollbackOn(java.lang.Throwable)
*/
@Override
public boolean rollbackOn(Throwable ex) {
RollbackRuleAttribute winner = null;
int deepest = Integer.MAX_VALUE;
if (this.rollbackRules != null) {
for (RollbackRuleAttribute rule : this.rollbackRules) {
int depth = rule.getDepth(ex);
if (depth >= 0 && depth < deepest) {
deepest = depth;
winner = rule;
}
}
}
// User superclass behavior (rollback on unchecked) if no rule matches.
if (winner == null) {
return super.rollbackOn(ex);
}
return !(winner instanceof NoRollbackRuleAttribute);
}
父类的 rollbackOn 方法
/**
* The default behavior is as with EJB: rollback on unchecked exception
* ({@link RuntimeException}), assuming an unexpected outcome outside of any
* business rules. Additionally, we also attempt to rollback on {@link Error} which
* is clearly an unexpected outcome as well. By contrast, a checked exception is
* considered a business exception and therefore a regular expected outcome of the
* transactional business method, i.e. a kind of alternative return value which
* still allows for regular completion of resource operations.
* <p>This is largely consistent with TransactionTemplate's default behavior,
* except that TransactionTemplate also rolls back on undeclared checked exceptions
* (a corner case). For declarative transactions, we expect checked exceptions to be
* intentionally declared as business exceptions, leading to a commit by default.
* @see org.springframework.transaction.support.TransactionTemplate#execute
*/
@Override
public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}
分析得出 事务的默认回滚是 RuntimeException 或者 Error
单元测试代码
@Test
public void testDefaultRule() {
RuleBasedTransactionAttribute rta = new RuleBasedTransactionAttribute();
assertThat(rta.rollbackOn(new RuntimeException())).isTrue();
assertThat(rta.rollbackOn(new MyRuntimeException(""))).isTrue();
assertThat(rta.rollbackOn(new Exception())).isFalse();
assertThat(rta.rollbackOn(new IOException())).isFalse();
}
从单元测试中可以发现,默认情况下 Exception 和 IOException 是不会被回滚的
总结
很多同学包括我在初次接触事务的时候,经常会发现自己手动 throws了一个Exception事务没有回滚