Spring数据库事务@Transactional知多少

720 阅读6分钟

问题背景

大多数业务场景中会大量使用到数据库事务,我们知道Spring提供了@Transactional注解来支持数据库的事务,那么这个注解会在那些情况下生效呢?下面通过源代码重点介绍下

首先看看 Transactional 的定义

@Target({ElementType.METHOD, ElementType.TYPE})

public @interface Transactional {


// 事务传播机制
Propagation propagation() default Propagation.REQUIRED;

// 事务的隔离级别
Isolation isolation() default Isolation.DEFAULT;

/**
 * 以下为异常处理 rollback 机制
 *
 */
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};


Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};

@Transactional 是基于AOP技术的数据库事务实现,Propagation是定义了如何使用数据库事务,Spring中七种Propagation类的事务属性详解:

  • REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

  • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。

  • MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。

  • REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。

  • NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

  • NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

  • NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。

AnnotationTransactionAttributeSource

继承自AbstractFallbackTransactionAttributeSource和接口TransactionAttributeSource

@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    if (method.getDeclaringClass() == Object.class) {
        return null;
    }
    //查找缓存
    Object cacheKey = getCacheKey(method, targetClass);
    TransactionAttribute cached = this.attributeCache.get(cacheKey);
    if (cached != null) {
        if (cached == NULL_TRANSACTION_ATTRIBUTE) {
            return null;
        }else {
            return cached;
        }
    }else {
        TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
        if (txAttr == null) {
            this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
        }else {
            String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
            if (txAttr instanceof DefaultTransactionAttribute) {
                ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
            }
            this.attributeCache.put(cacheKey, txAttr);
        }
        return txAttr;
    }
}

@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
        // 修饰 必须是 public
        return null;
    }
    Method specificMethod = AopUtils.*getMostSpecificMethod*(method, targetClass);
    TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
    if (txAttr != null) {
        return txAttr;
    }
    txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
    if (txAttr != null && ClassUtils.*isUserLevelMethod*(method)) {
        return txAttr;
    }
    if (specificMethod != method) {
        txAttr = findTransactionAttribute(method);
        if (txAttr != **null**) {
            return txAttr;
        }
        txAttr = findTransactionAttribute(method.getDeclaringClass());
        if (txAttr != **null** && ClassUtils.*isUserLevelMethod*(method)) {
            return txAttr;
        }
    }
    return** null;
}
TransactionAspectSupport.class
private static final ThreadLocal<TransactionInfo> transactionInfoHolder = new NamedThreadLocal<>("Current aspect-driven transaction");

// 事务管理
@Nullable
private PlatformTransactionManager transactionManager;

// 事务属性配置
@Nullable
private TransactionAttributeSource transactionAttributeSource;

@Nullable
private BeanFactory beanFactory;

// 缓存
private final ConcurrentMap<Object, PlatformTransactionManager> transactionManagerCache = new ConcurrentReferenceHashMap<>(4);
@Nullable

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation) throws Throwable 
{
    // If the transaction attribute is null, the method is non-transactional.
    // 获取方法定义的 Transaction 事物相关的属性
    TransactionAttributeSource tas = getTransactionAttributeSource();
    final TransactionAttribute txAttr = (tas != null ?tas.getTransactionAttribute(method, targetClass) : null);
    final PlatformTransactionManager tm = determineTransactionManager(txAttr);
    // 获取需要切入的方法
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

    if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
    // 新建 TransactionInfo 对象
        TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
        Object retVal = null

        try {
            // 执行切入
            retVal = invocation.proceedWithInvocation();
            }catch (Throwable ex) {
            // 异常处理
                completeTransactionAfterThrowing(txInfo, ex);
                throw ex;
            }finally {
                // 清除缓存信息
                cleanupTransactionInfo(txInfo);
            }
            //执行 Commit
            commitTransactionAfterReturning(txInfo);
            return retVal;
        }
    else {
        final ThrowableHolder throwableHolder = new ThrowableHolder();
        try {
            Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
            TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
            try {
                return invocation.proceedWithInvocation();
            }catch(Throwable ex) {
                // 自定义rallback异常处理
                if (txAttr.rollbackOn(ex)) {
                    if (ex instanceof RuntimeException) {
                        throw (RuntimeException) ex;
                    }else{
                        throw new ThrowableHolderException(ex);
                    }
                } else {
                        throwableHolder.throwable = ex;
                        return  null;
                }
            }finally{
                cleanupTransactionInfo(txInfo);
            }});
            if (throwableHolder.throwable != null {
               throw throwableHolder.throwable;
            }
            return result;
       }catch (ThrowableHolderException ex) {
            throw ex.getCause();
       }catch (TransactionSystemException ex2) {
            if (throwableHolder.throwable != null) {
                logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                ex2.initApplicationException(throwableHolder.throwable);
            }
            throw ex2;
       }catch(Throwable ex2) {
            if (throwableHolder.throwable != null) {
                logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
            }
            throw ex2;
       }
   }
}

/**
* 获取对应transaction的Manager
*/
@Nullable
protected PlatformTransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
    if (txAttr == null || this.beanFactory == null) {
        return getTransactionManager();
    }
    //. 按照 qualifier 超找 manager
    String qualifier = txAttr.getQualifier();

    if (StringUtils.hasText(qualifier)) {
        return determineQualifiedTransactionManager(this.beanFactory, qualifier);
    }else if (StringUtils.hasText(this.transactionManagerBeanName)) {
        return determineQualifiedTransactionManager(**this**.beanFactory, this.transactionManagerBeanName);
    }else {
         // 创建Manager 并缓存
        PlatformTransactionManager defaultTransactionManager = getTransactionManager();
        if (defaultTransactionManager == null) {
            defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
            if (defaultTransactionManager == null) {
                defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
                this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
            }
        }
        return defaultTransactionManager;
   }
}

// 获取方法名称
private String methodIdentification(Method method, @Nullable Class<?> targetClass,@Nullable TransactionAttribute txAttr) {
    String methodIdentification = methodIdentification(method, targetClass);
    if (methodIdentification == null) {
        if (txAttr instanceof DefaultTransactionAttribute) {
            methodIdentification = ((DefaultTransactionAttribute) txAttr).getDescriptor();
        }
        if (methodIdentification == null) {
            methodIdentification = ClassUtils.*getQualifiedMethodName*(method, targetClass);
        }
    }
    return methodIdentification;

}

// TransactionAttribute 生成对应的 TransactionInfo 此处为线程级别的TransactionInfo
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// If no name specified, apply method identification as transaction name.
    if (txAttr != null && txAttr.getName() == null) {
        txAttr = new DelegatingTransactionAttribute(txAttr) {
            @Override
            public String getName() {
                return joinpointIdentification;
            }
        };
    }
    TransactionStatus status = null;
    if (txAttr != null) {
        if (tm != null) {
            status = tm.getTransaction(txAttr);
        }else {
            if (logger.isDebugEnabled()) {
                logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +"] because no transaction manager has been configured");
           }
        }
    }
    return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

// 生成TransactionInfo,并维护status
protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,@Nullable TransactionAttribute txAttr, String joinpointIdentification,@Nullable TransactionStatus status) {
    TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
    if (txAttr != null) {
        if (logger.isTraceEnabled()) {
            logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
        }
        txInfo.newTransactionStatus(status);
    }else {
        if (logger.isTraceEnabled())
            logger.trace("Don't need to create transaction for [" + joinpointIdentification +"]: This method isn't transactional.");
    }
    txInfo.bindToThread();
    return txInfo;
}

protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
    if (txInfo != null) {
        txInfo.restoreThreadLocalStatus();
    }
}

private void restoreThreadLocalStatus() {
    transactionInfoHolder.set(this.oldTransactionInfo);
}

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        if (logger.isTraceEnabled()) {
            logger.trace("Completing transaction for [" +txInfo.getJoinpointIdentification() + "]");
        }
       //此处才是真正 执行 commit txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
     }
}
AbstractPlatformTransactionManager.class

实际Jdbc DataSource 中实现了DataSourceTransactionManager

@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()) {
        // 处理Rollback
        if (defStatus.isDebug()) {
            logger.debug("Transactional code has requested rollback");
        }
        processRollback(defStatus, false);
        return;
    }
    if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
        if (defStatus.isDebug()) {
            logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
        }
        processRollback(defStatus, true);
        return;
    }
    // 实际执行commit
    processCommit(defStatus);
}

// rollback 处理
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
    try {
        boolean unexpectedRollback = unexpected;
        try {
            // 生命周期 rollback 开始前
            triggerBeforeCompletion(status);
            if (status.hasSavepoint()) {
                if (status.isDebug()) {
                    logger.debug("Rolling back transaction to savepoint");
                }
                status.rollbackToHeldSavepoint();
            }else if (status.isNewTransaction()) {
                if (status.isDebug()) {
                    logger.debug("Initiating transaction rollback");
                }
                // 实际的rollback 触发
                doRollback(status);
            }else {
                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");
               }
               if (!isFailEarlyOnGlobalRollbackOnly()) {
                    unexpectedRollback = **false**;
               }
          }
        }catch (RuntimeException | Error ex) {
            triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
                throw ex;
       }
       // 生命周期 rollback 出发之后
       triggerAfterCompletion(status, TransactionSynchronization.***STATUS_ROLLED_BACK***);
    // 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);
   }
}

// 清理资源,处理transaction中断
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
    status.setCompleted();
    //tm 清理
    if (status.isNewSynchronization()) {
        TransactionSynchronizationManager.clear();
    }
    if (status.isNewTransaction()) {
        // 状态通知
        doCleanupAfterCompletion(status.getTransaction());
    }
    if (status.getSuspendedResources() != null) {
        //处理中断恢复工作
        if (status.isDebug()) {
            logger.debug("Resuming suspended transaction after completion of inner transaction");
        }
        Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
        resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
    }
}

// commit 处理
private void processCommit(DefaultTransactionStatus status) **throws** TransactionException {
    try {
        boolean beforeCompletionInvoked = false;
        try {
            boolean unexpectedRollback = false;
            // 由子类实现
            prepareForCommit(status);
            triggerBeforeCommit(status);
            triggerBeforeCompletion(status);
            beforeCompletionInvoked = true;
            if (status.hasSavepoint()) {
                if (status.isDebug()) {
                    logger.debug("Releasing transaction savepoint");
                }                
                unexpectedRollback = status.isGlobalRollbackOnly();
                status.releaseHeldSavepoint();
            }else if (status.isNewTransaction()) {
                if (status.isDebug()) {
                    logger.debug("Initiating transaction commit");
                }
                unexpectedRollback = status.isGlobalRollbackOnly();
                // 由子类实现
                doCommit(status);
            }else if (isFailEarlyOnGlobalRollbackOnly()) {
                unexpectedRollback = status.isGlobalRollbackOnly();
            }
            if (unexpectedRollback) {
                throw new UnexpectedRollbackException("Transaction silently rolled back because it has been marked as rollback-only");
            }
        }catch (UnexpectedRollbackException ex) {
            triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
            throw ex;
        }catch (TransactionException ex) {
            if (isRollbackOnCommitFailure()) {
                doRollbackOnCommitException(status, ex);
            }else {
                triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
            }
            throw ex;
        }catch (RuntimeException | Error ex) {
            if (!beforeCompletionInvoked) {
                triggerBeforeCompletion(status);
            }
            // rollback 处理,最终由子类实现 doRollback 方法
            doRollbackOnCommitException(status, ex);
            throw ex;
        }
        try {
            triggerAfterCommit(status);
        }finally {
            triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
        }
    }finally {
        cleanupAfterCompletion(status);
    }
}
TransactionSynchronizationUtils.class 帮助util类
public static void triggerBeforeCommit(boolean readOnly)
public static void triggerBeforeCompletion();
public static void triggerAfterCommit();
public static void invokeAfterCommit(@Nullable List<TransactionSynchronization> synchronizations)
public static void triggerAfterCompletion(int completionStatus)
public static void invokeAfterCompletion(@Nullable List<TransactionSynchronization> synchronizations,int completionStatus)
DataSourceTransactionManager 数据库相关TM
protected void doBegin(Object transaction, TransactionDefinition definition)
protected Object doSuspend(Object transaction)
protected void doResume(@Nullable Object transaction, Object suspendedResources)
protected void doCommit(DefaultTransactionStatus status)
protected void doRollback(DefaultTransactionStatus status)
protected void doSetRollbackOnly(DefaultTransactionStatus status)
protected void doCleanupAfterCompletion(Object transaction)

@Transactional使用场景

  1. @Transactional 是基于Java AOP 机制,所有对于 final 修饰的方法 不起作用,因为方法无法通过cglib和aop等生成代理类
  2. @Transactional 修饰的方法 必须为 public,其他方法都无法生成事务;这里主要还是继承带来的可见性导致
  3. @Transactional 修饰的方法所在类必须是Spring管理的Bean对象;因为Transaction事务使用了Bean的生命周期
  4. @Transactional 不支持多线程,这是因为事务是绑定在DataSource的数据库连接上,不同线程中的数据库连接实例不同。ThreadLocal管理connect

@Transactional 事务回滚总结

  1. 目前只有这三种传播特性才会创建新事务:REQUIRED,REQUIRES_NEW,NESTED。其他的都不支持事务,会抛出异常
  2. 事务的回滚是基于异常的处理,所有事物的回滚处理中,需要抓取到异常,这样用户代码中不应该处理异常,一旦处理了异常,事务Manager无法感知
  3. 自定义rollback异常需要根据实际情况继承,否则rollback的时候无法抓取对应的异常,从而让回滚动作失效
  4. 特别需要关注的是当一个事务中存在多个方法,或者存在嵌套的情况,需要防止过度回滚,需要在嵌套层直接处理异常。不在通知到上层事物进行回滚操作;这个机制在叫做savepoint保存点。在嵌套使用的情况下需要注意回滚的粒度

最后 @Transactional 虽然使用特别方便轻量,但是到来的问题也不少,有时候特别不好定位问题。所以使用需要谨慎。