我们常常在事务注解中,定义rollbackFor 为事务定义异常的类型。
@Transactional(rollbackFor = Exception.class) public ResultupdateArticle(Long articleId, ArticleCreateRequest request) // TODO code. } Spring(6.2.7)
public class RuleBasedTransactionAttribute extends DefaultTransactionAttribute implements Serializable {
@Override
public boolean rollbackOn(Throwable ex) {
RollbackRuleAttribute winner = null;
int deepest = Integer.MAX_VALUE;
// 1. 检查是否有显式配置的回滚规则
if (this.rollbackRules != null) {
for (RollbackRuleAttribute rule : this.rollbackRules) {
int depth = rule.getDepth(ex);
// 2. 检查异常是否匹配回滚规则
if (depth >= 0 && depth < deepest) {
deepest = depth;
winner = rule; // 匹配则回滚
}
}
}
// User superclass behavior (rollback on unchecked) if no rule matches.
if (winner == null) {
// 3. 没有匹配规则时使用默认行为
return super.rollbackOn(ex);
}
return !(winner instanceof NoRollbackRuleAttribute);
}
}
public class RollbackRuleAttribute implements Serializable{
public int getDepth(Throwable exception) {
// 递归调用
return getDepth(exception.getClass(), 0);
}
private int getDepth(Class> exceptionType, int depth) {
if (this.exceptionType != null) {
// 1. 检查当前异常类是否匹配规则
if (this.exceptionType.equals(exceptionType)) {
// Found it!
return depth;
}
}
// 2. 根据名称匹配
else if (exceptionType.getName().contains(this.exceptionPattern)) {
// Found it!
return depth;
}
// If we've gone as far as we can go and haven't found it...
// 3. 递归检查父类 (RuntimeException->Exception->Throwable)
if (exceptionType == Throwable.class) {
// 没有找到.
return -1;
}
// 递归
return getDepth(exceptionType.getSuperclass(), depth + 1);
}
}
public class DefaultTransactionAttribute extends DefaultTransactionDefinition implements TransactionAttribute {
@Override
public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}
}
public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
Propagation propagation = attributes.getEnum("propagation");
rbta.setPropagationBehavior(propagation.value());
Isolation isolation = attributes.getEnum("isolation");
rbta.setIsolationLevel(isolation.value());
rbta.setTimeout(attributes.getNumber("timeout").intValue());
String timeoutString = attributes.getString("timeoutString");
Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,
"Specify 'timeout' or 'timeoutString', not both");
rbta.setTimeoutString(timeoutString);
rbta.setReadOnly(attributes.getBoolean("readOnly"));
rbta.setQualifier(attributes.getString("value"));
rbta.setLabels(Set.of(attributes.getStringArray("label")));
List rollbackRules = new ArrayList<>();
// 解析 rollbackFor 配置
for (Class> rbRule : attributes.getClassArray("rollbackFor")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
// 解析 noRollbackFor 配置
for (Class> rbRule : attributes.getClassArray("noRollbackFor")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
rbta.setRollbackRules(rollbackRules);
return rbta;
}
}
TransactionAspectSupport#completeTransactionAfterThrowing
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
}
// 检查是否需要回滚
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
// 执行回滚
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
// 记录日志并处理回滚失败
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}
else {
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
try {
// 提交事务(即使有异常)
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by commit exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
}
}
}
RollbackRuleAttribute#getDepth
private int getDepth(Class> exceptionType, int depth) {
if (this.exceptionType != null) {
if (this.exceptionType.equals(exceptionType)) {
// Found it!
return depth;
}
}
else if (exceptionType.getName().contains(this.exceptionPattern)) {
// Found it!
return depth;
}
// If we've gone as far as we can go and haven't found it...
if (exceptionType == Throwable.class) {
return -1;
}
return getDepth(exceptionType.getSuperclass(), depth + 1);
}
AbstractPlatformTransactionManager#processRollback
public abstract class AbstractPlatformTransactionManager
implements PlatformTransactionManager, ConfigurableTransactionManager, Serializable {
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected;
boolean rollbackListenerInvoked = false;
try {
triggerBeforeCompletion(status);
// 嵌套事务回滚处理
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
this.transactionExecutionListeners.forEach(listener -> listener.beforeRollback(status));
rollbackListenerInvoked = true;
status.rollbackToHeldSavepoint();
}
// 新事务回滚
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
this.transactionExecutionListeners.forEach(listener -> listener.beforeRollback(status));
rollbackListenerInvoked = true;
doRollback(status);
}
else {
// Participating in larger transaction
// 参与现有事务
if (status.hasTransaction()) {
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}
doSetRollbackOnly(status);
}
else {
if (status.isDebug()) {
logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
}
}
}
else {
logger.debug("Should roll back transaction but cannot - no transaction available");
}
// Unexpected rollback only matters here if we're asked to fail early
if (!isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = false;
}
}
}
catch (RuntimeException | Error ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
if (rollbackListenerInvoked) {
this.transactionExecutionListeners.forEach(listener -> listener.afterRollback(status, ex));
}
throw ex;
}
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
if (rollbackListenerInvoked) {
this.transactionExecutionListeners.forEach(listener -> listener.afterRollback(status, null));
}
// Raise UnexpectedRollbackException if we had a global rollback-only marker
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction rolled back because it has been marked as rollback-only");
}
}
finally {
cleanupAfterCompletion(status);
}
}
}
当配置 @Transactional(rollbackFor = Exception.class)
时:
RollbackRuleAttribute rule = new RollbackRuleAttribute(Exception.class);
Exception
的子类都会匹配(深度 >= 0)SQLException
、IOException
等受检异常RuntimeException
及其子类RuntimeException
和 Error
@Transactional( rollbackFor = Exception.class, noRollbackFor = BusinessException.class )
BusinessException
不会触发回滚。Exception
子类都会触发回滚
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private PaymentService paymentService;
// 配置对所有Exception回滚
@Transactional(rollbackFor = Exception.class)
public void processOrder(Order order) throws PaymentException {
// 保存订单
orderRepository.save(order);
try {
// 支付操作(可能抛出受检异常)
paymentService.processPayment(order);
} catch (PaymentException ex) {
// 记录日志但继续处理
log.error("支付处理失败", ex);
}
// 发送通知(可能抛出IOException)
sendOrderConfirmation(order);
}
private void sendOrderConfirmation(Order order) throws IOException {
// 发送邮件或短信
if (someErrorCondition) {
throw new IOException("通知发送失败");
}
}
}
代码解析:
1.PaymentException
场景
rollbackFor = Exception.class
→ 触发回滚sendOrderConfirmation()
抛出 IOException
2.数据库操作失败:
orderRepository.save()
抛出 DataAccessException
(RuntimeException)
@Transactional
注解rollbackFor
转换为 RollbackRuleAttribute
集合RuleBasedTransactionAttribute
整合所有规则Connection.rollback()
DataSourceTransactionManager
)实现rollbackFor = Exception.class
不包含 Error@Transactional(rollbackFor = {Exception.class, Error.class})
class CustomException implements MyBusinessException
rollbackFor = MyBusinessException.class
会匹配
rollbackFor = Throwable.class
)(不建议 ×)注意版本差异,spring 每个版本的实现都略有不同。