Back to Javatutorial

Spring事务(六):事务的隔离级别与传播方式的处理04

docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(六):事务的隔离级别与传播方式的处理04.md

1.0.011.2 KB
Original Source

ǡĸ뼶봫ʽĴĵ 4 ƪģǼ

3.6 ִоҵ

£

retVal = invocation.proceedWithInvocation();

ջõҵ񷽷 UserService#insertIJ̽һùȥģҪ˽ù̵СԲο aop ز

3.7 쳣ع

쳣ķΪ TransactionAspectSupport#completeTransactionAfterThrowing£

protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        // 쳣ϲŻع
        if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
            try {
                txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
            }
            catch (...) {
                ...
            }
        }
        else {
            try {
                // 쳣ϣʹִгҲύ
                txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
            }
            catch (...) {
                ...
            }
        }
    }
}

쳣ֱӽлعģҪж쳣ͣҪع쳣Żع

жϵǰ쳣ǷҪع

ж쳣ǷϵķΪ RuleBasedTransactionAttribute#rollbackOn

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;
            }
        }
    }
    if (winner == null) {
        return super.rollbackOn(ex);
    }
    return !(winner instanceof NoRollbackRuleAttribute);
}

ȡķΪ RollbackRuleAttribute#getDepth(Throwable)£

public int getDepth(Throwable ex) {
    return getDepth(ex.getClass(), 0);
}

private int getDepth(Class<?> exceptionClass, int depth) {
    if (exceptionClass.getName().contains(this.exceptionName)) {
        // Found it!
        return depth;
    }
    // If we've gone as far as we can go and haven't found it...
    if (exceptionClass == Throwable.class) {
        return -1;
    }
    // ݹȡ
    return getDepth(exceptionClass.getSuperclass(), depth + 1);
}

ʵֺܼ򵥣ǵݹȡ exception ĸ࣬ҵ˾ͷصݹĴҵ Throwableͷ - 1.

֮ʹжǷҪعԭûع쳣ʱ쳣ƣ

public @interface Transactional {
    ...

    // עַ
    String[] rollbackForClassName() default {};
}

˲ʹ ex instanceof Exception ķʽжܷع

RuleBasedTransactionAttribute#rollbackOn е RollbackRuleAttribute NoRollbackRuleAttribute ɶأ rollbackFor noRollbackFor İװ࣬ SpringTransactionAnnotationParser#parseTransactionAnnotation(AnnotationAttributes) ã£

protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
    RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
    ...
    // ع쳣
    List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
    for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
        rollbackRules.add(new RollbackRuleAttribute(rbRule));
    }
    for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
        rollbackRules.add(new RollbackRuleAttribute(rbRule));
    }
    // ع쳣
    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;
}

ع

ع AbstractPlatformTransactionManager#rollback дݿĻع⣬һЩصǾͲˣֱӿؼĻع롣ǰķĴʱഫǻع񣬲 PROPAGATION_NESTED ⣬ǻع㣬Ƿֱؼ룺

  1. ع

    عķΪ DataSourceTransactionManager#doRollbackյõ java.sql.Connection ķ

    protected void doRollback(DefaultTransactionStatus status) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
        // ȡӣConnection Ϊ java.sql.Connection
        Connection con = txObject.getConnectionHolder().getConnection();
        try {
            con.rollback();
        }
        catch (SQLException ex) {
            throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
        }
    }
    
    
  2. ع عIJ AbstractTransactionStatus#rollbackToHeldSavepoint У

    public void rollbackToHeldSavepoint() throws TransactionException {
        Object savepoint = getSavepoint();
        if (savepoint == null) {
            throw new TransactionUsageException(...);
        }
        // ع
        getSavepointManager().rollbackToSavepoint(savepoint);
        // ͷű
        getSavepointManager().releaseSavepoint(savepoint);
        // Ϊnull
        setSavepoint(null);
    }
    
    

    Ҫعͷű㡣

    عIJ JdbcTransactionObjectSupport#rollbackToSavepoint

    public void rollbackToSavepoint(Object savepoint) throws TransactionException {
        ConnectionHolder conHolder = getConnectionHolderForSavepoint();
        try {
            conHolder.getConnection().rollback((Savepoint) savepoint);
            conHolder.resetRollbackOnly();
        }
        catch (Throwable ex) {
            throw new TransactionSystemException("Could not roll back to JDBC savepoint", ex);
        }
    }
    
    

    ͷűIJ JdbcTransactionObjectSupport#releaseSavepoint

    public void releaseSavepoint(Object savepoint) throws TransactionException {
        ConnectionHolder conHolder = getConnectionHolderForSavepoint();
        try {
            conHolder.getConnection().releaseSavepoint((Savepoint) savepoint);
        }
        catch (Throwable ex) {
            logger.debug("Could not explicitly release JDBC savepoint", ex);
        }
    }
    
    

    նǵ java.sql.Connection ṩķɲ

ύύĴΪ

txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());

Ǹһֱ AbstractPlatformTransactionManager#processCommit

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
    try {
        ...

        try {
            if (status.hasSavepoint()) {
                ...
                unexpectedRollback = status.isGlobalRollbackOnly();
                // 1\. ͷű
                status.releaseHeldSavepoint();
            }
            else if (status.isNewTransaction()) {
                ...
                unexpectedRollback = status.isGlobalRollbackOnly();
                // 2\. ύ
                doCommit(status);
            }
            else if (isFailEarlyOnGlobalRollbackOnly()) {
                ...
            }

            ...
        }
        catch (...) {
            ...
        }
    }
    finally {
        // 3\. ɲָ(ָݿ)
        cleanupAfterCompletion(status);
    }
}

Ϸʡ˴룬 TransactionSynchronization صصģǾۼҪ

  1. ͷű㣺ѾˣͲٷ
  2. ύύУһǻᷢǵ java.sql.Connection ṩķ
  3. ɲȽҪӵϢָӾе

ύֱӽմ룺DataSourceTransactionManager#doCommit

protected void doCommit(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    // ȡӣConnection Ϊ java.sql.Connection
    Connection con = txObject.getConnectionHolder().getConnection();
    try {
        // ύ
        con.commit();
    }
    catch (SQLException ex) {
        throw new TransactionSystemException("Could not commit JDBC transaction", ex);
    }
}

Ҳǵ java.sql.Connection ṩķ

ɲĴ AbstractPlatformTransactionManager#cleanupAfterCompletion

private void cleanupAfterCompletion(DefaultTransactionStatus status) {
    status.setCompleted();
    if (status.isNewSynchronization()) {
        TransactionSynchronizationManager.clear();
    }
    if (status.isNewTransaction()) {
        // ӣӣر
        doCleanupAfterCompletion(status.getTransaction());
    }
    // йлָ
    if (status.getSuspendedResources() != null) {
        Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
        // ָ
        resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
    }
}

DataSourceTransactionManager#doCleanupAfterCompletion :

protected void doCleanupAfterCompletion(Object transaction) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;

    // ƳԴӵİ󶨹ϵ
    if (txObject.isNewConnectionHolder()) {
        TransactionSynchronizationManager.unbindResource(obtainDataSource());
    }

    // ӣǽϢִָǰ״̬
    Connection con = txObject.getConnectionHolder().getConnection();
    try {
        if (txObject.isMustRestoreAutoCommit()) {
            con.setAutoCommit(true);
        }
        DataSourceUtils.resetConnectionAfterTransaction(
                con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
    }
    catch (Throwable ex) {
        logger.debug("Could not reset JDBC Connection after transaction", ex);
    }
    // ӣر
    if (txObject.isNewConnectionHolder()) {
        // յõ java.sql.Connection#close
        DataSourceUtils.releaseConnection(con, this.dataSource);
    }

    txObject.getConnectionHolder().clear();
}

ĻָҲ resume(...) 󣬷յõ DataSourceTransactionManager#doResume £

@Override
protected void doResume(@Nullable Object transaction, Object suspendedResources) {
    // Դݿ뵱ǰ̰߳
    TransactionSynchronizationManager.bindResource(obtainDataSource(), suspendedResources);
}

һ󣬴ʱԴ֮ǰԴˡ

3.8 Ϣ

ijЩʽ£ PROPAGATION_REQUIRES_NEWҪǰȻ󴴽µִɺҪָԭϢǽǰϢָΪϢֻǻָϢݿӲָ

public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {

    // ŵǰʹõϢ
    private static final ThreadLocal<TransactionInfo> transactionInfoHolder =
            new NamedThreadLocal<>("Current aspect-driven transaction");

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

    /**
     * TransactionInfo: Ϣ
     */
    protected static final class TransactionInfo {

        // ǰ״̬
        @Nullable
        private TransactionStatus transactionStatus;

        // ɵϢҲǹϢ
        @Nullable
        private TransactionInfo oldTransactionInfo;

        ...

        private void restoreThreadLocalStatus() {
            // ΪɵϢ
            transactionInfoHolder.set(this.oldTransactionInfo);
        }

        ...
    }

}

ԿTransactionInfo ԻһϢoldTransactionInfo ijԱûһϢʱֻǼ򵥵ؽ oldTransactionInfo õΪ transactionInfoHolder ThreadLocal

3.9 ύ

ύĴΪ TransactionAspectSupport#commitTransactionAfterReturning£

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
    // ж״̬
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        // ύǰѾ
        txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
    }
}

ڸ÷Уֿд룺

txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());

Ѿ쳣ύзˣͲٷˡ


ԭӣhttps://my.oschina.net/funcy/blog/4947800 ߸ˮƽд֮ӭָԭףҵתϵ߻Ȩҵתע