By default, a transaction will be rolling back on RuntimeException and Error but not on checked exceptions (business exceptions). See DefaultTransactionAttribute.rollbackOn(Throwable) for a detailed explanation.
在B方法上加了@Transactional 注解,它默认有RuntimeException 或Error的 时候会自动回滚,所以在catch 里面的UPDATE执行时就会有异常抛出。这种在catch里面做update的调用也很奇葩,会有很大隐患。
By default, a transaction will be rolling back on RuntimeException and Error but not on checked exceptions (business exceptions). See DefaultTransactionAttribute.rollbackOn(Throwable) for a detailed explanation.
在B方法上加了@Transactional 注解,它默认有RuntimeException 或Error的 时候会自动回滚,所以在catch 里面的UPDATE执行时就会有异常抛出。这种在catch里面做update的调用也很奇葩,会有很大隐患。
有一种原因是:声明式事务设置的是 PROPAGATION_REQUIRED 级别,c的事务加入到b中,c出现运行时异常,抛出异常时transaction被设置为rollback-only了, 但在b中异常又被处理了, b 执行完后,transaction会执commit操作,但是transaction已经被设置为rollback-only了。
@Override
public final void commit(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
processRollback(defStatus);
return;
}
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
processRollback(defStatus);
// Throw UnexpectedRollbackException only at outermost transaction boundary
// or if explicitly asked to.
if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
throw new UnexpectedRollbackException(
"Transaction rolled back because it has been marked as rollback-only");
}
return;
}
processCommit(defStatus);
}