Spring Corbar事务源码 以及连接泄露分析

事务开启

通过注解@Transactional可以开启事务。

开启事务后,Spring代理时,会通过TransactionAspectSupport来注入,具体的方法和代码如下:

1
protected Object invokeWithinTransaction(Method method, Class targetClass, final InvocationCallback invocation)
2
            throws Throwable {
3
4
        // If the transaction attribute is null, the method is non-transactional.
5
        final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
6
        final PlatformTransactionManager tm = determineTransactionManager(txAttr);
7
        final String joinpointIdentification = methodIdentification(method, targetClass);
8
9
        if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
10
            // Standard transaction demarcation with getTransaction and commit/rollback calls.
11
            TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
12
            Object retVal = null;
13
            try {
14
                // This is an around advice: Invoke the next interceptor in the chain.
15
                // This will normally result in a target object being invoked.
16
                retVal = invocation.proceedWithInvocation();
17
            }
18
            catch (Throwable ex) {
19
                // target invocation exception
20
                completeTransactionAfterThrowing(txInfo, ex);
21
                throw ex;
22
            }
23
            finally {
24
                cleanupTransactionInfo(txInfo);
25
            }
26
            commitTransactionAfterReturning(txInfo);
27
            return retVal;
28
        }
29
30
        else {
31
            // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
32
            try {
33
                Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
34
                        new TransactionCallback<Object>() {
35
                            public Object doInTransaction(TransactionStatus status) {
36
                                TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
37
                                try {
38
                                    return invocation.proceedWithInvocation();
39
                                }
40
                                catch (Throwable ex) {
41
                                    if (txAttr.rollbackOn(ex)) {
42
                                        // A RuntimeException: will lead to a rollback.
43
                                        if (ex instanceof RuntimeException) {
44
                                            throw (RuntimeException) ex;
45
                                        }
46
                                        else {
47
                                            throw new ThrowableHolderException(ex);
48
                                        }
49
                                    }
50
                                    else {
51
                                        // A normal return value: will lead to a commit.
52
                                        return new ThrowableHolder(ex);
53
                                    }
54
                                }
55
                                finally {
56
                                    cleanupTransactionInfo(txInfo);
57
                                }
58
                            }
59
                        });
60
61
                // Check result: It might indicate a Throwable to rethrow.
62
                if (result instanceof ThrowableHolder) {
63
                    throw ((ThrowableHolder) result).getThrowable();
64
                }
65
                else {
66
                    return result;
67
                }
68
            }
69
            catch (ThrowableHolderException ex) {
70
                throw ex.getCause();
71
            }
72
        }
73
    }
最终通过createTransactionIfNecessary来创建事务。
1
    protected TransactionInfo createTransactionIfNecessary(
2
            PlatformTransactionManager tm, TransactionAttribute txAttr, final String joinpointIdentification) {
3
4
        // If no name specified, apply method identification as transaction name.
5
        if (txAttr != null && txAttr.getName() == null) {
6
            txAttr = new DelegatingTransactionAttribute(txAttr) {
7
                @Override
8
                public String getName() {
9
                    return joinpointIdentification;
10
                }
11
            };
12
        }
13
14
        TransactionStatus status = null;
15
        if (txAttr != null) {
16
            if (tm != null) {
17
                status = tm.getTransaction(txAttr);
18
            }
19
            else {
20
                if (logger.isDebugEnabled()) {
21
                    logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
22
                            "] because no transaction manager has been configured");
23
                }
24
            }
25
        }
26
        return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
27
    }
如果是corbar分库,则会根据每个shards进行开启事务。
corbarclient重写了Spring的事务管理,开启事务通过BestEffortMultiDataSourceTransactionManager来实现。
1
    @Override
2
    protected void doBegin(Object o, TransactionDefinition transactionDefinition) throws TransactionException {
3
        List<TransactionStatus> statusList = (List<TransactionStatus>) o;
4
        for (AbstractPlatformTransactionManager transactionManager : transactionManagers) {
5
            statusList.add(transactionManager.getTransaction(transactionDefinition));
6
        }
7
    }
通过获取多个shard来实现事务。
1
    protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
2
        if (status.isNewSynchronization()) {
3
            TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
4
            TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
5
                    (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) ?
6
                            definition.getIsolationLevel() : null);
7
            TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
8
            TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
9
            TransactionSynchronizationManager.initSynchronization();
10
        }
11
    }
最终TransactionAspectSupport  prepareTransactionInfo。
1
protected TransactionInfo prepareTransactionInfo(PlatformTransactionManager tm,
2
            TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {
3
4
        TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
5
        if (txAttr != null) {
6
            // We need a transaction for this method
7
            if (logger.isTraceEnabled()) {
8
                logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
9
            }
10
            // The transaction manager will flag an error if an incompatible tx already exists
11
            txInfo.newTransactionStatus(status);
12
        }
13
        else {
14
            // The TransactionInfo.hasTransaction() method will return
15
            // false. We created it only to preserve the integrity of
16
            // the ThreadLocal stack maintained in this class.
17
            if (logger.isTraceEnabled())
18
                logger.trace("Don't need to create transaction for [" + joinpointIdentification +
19
                        "]: This method isn't transactional.");
20
        }
21
22
        // We always bind the TransactionInfo to the thread, even if we didn't create
23
        // a new transaction here. This guarantees that the TransactionInfo stack
24
        // will be managed correctly even if no transaction was created by this aspect.
25
        txInfo.bindToThread();
26
        return txInfo;
27
    }
1
private void bindToThread() {
2
            // Expose current TransactionStatus, preserving any existing TransactionStatus
3
            // for restoration after this transaction is complete.
4
            this.oldTransactionInfo = transactionInfoHolder.get();
5
            transactionInfoHolder.set(this);
6
        }
7
1
    /**
2
     * Holder to support the {@code currentTransactionStatus()} method,
3
     * and to support communication between different cooperating advices
4
     * (e.g. before and after advice) if the aspect involves more than a
5
     * single method (as will be the case for around advice).
6
     */
7
    private static final ThreadLocal<TransactionInfo> transactionInfoHolder =
8
            new NamedThreadLocal<TransactionInfo>("Current aspect-driven transaction");
需要注意此处的ThreadLocal,这里绑定了我们需要的事务,方便在当前before和after切面后进行处理。
事务提交
在TransactionAspectSupport   invokeWithTransaction方法开启事务并执行完数据库操作后在finally语句中进行对事务的提交clean处理.
1
    protected void cleanupTransactionInfo(TransactionInfo txInfo) {
2
        if (txInfo != null) {
3
            txInfo.restoreThreadLocalStatus();
4
        }
5
    }
1
    private void restoreThreadLocalStatus() {
2
            // Use stack to restore old transaction TransactionInfo.
3
            // Will be null if none was set.
4
            transactionInfoHolder.set(this.oldTransactionInfo);
5
        }
最终事务的提交
1
    protected void commitTransactionAfterReturning(TransactionInfo txInfo) {
2
        if (txInfo != null && txInfo.hasTransaction()) {
3
            if (logger.isTraceEnabled()) {
4
                logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
5
            }
6
            txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
7
        }
8
    }
提交操作
1
public final void commit(TransactionStatus status) throws TransactionException {
2
        if (status.isCompleted()) {
3
            throw new IllegalTransactionStateException(
4
                    "Transaction is already completed - do not call commit or rollback more than once per transaction");
5
        }
6
7
        DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
8
        if (defStatus.isLocalRollbackOnly()) {
9
            if (defStatus.isDebug()) {
10
                logger.debug("Transactional code has requested rollback");
11
            }
12
            processRollback(defStatus);
13
            return;
14
        }
15
        if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
16
            if (defStatus.isDebug()) {
17
                logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
18
            }
19
            processRollback(defStatus);
20
            // Throw UnexpectedRollbackException only at outermost transaction boundary
21
            // or if explicitly asked to.
22
            if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
23
                throw new UnexpectedRollbackException(
24
                        "Transaction rolled back because it has been marked as rollback-only");
25
            }
26
            return;
27
        }
28
29
        processCommit(defStatus);
30
    }
最终的提交交给corbar  BestEffortMultiDataSourceTransactionManager
1
    protected void doCommit(DefaultTransactionStatus defaultTransactionStatus) throws TransactionException {
2
        MultipleCauseException ex = new MultipleCauseException();
3
        List<TransactionStatus> statusList = (List<TransactionStatus>) defaultTransactionStatus.getTransaction();
4
        for (int i = transactionManagers.size() - 1; i >= 0; i--) {
5
            AbstractPlatformTransactionManager transactionManager = transactionManagers.get(i);
6
            TransactionStatus status = statusList.get(i);
7
            try {
8
                transactionManager.commit(status);
9
            } catch (TransactionException e) {
10
                ex.add(e);
11
            }
12
        }
13
        if (!ex.getCauses().isEmpty())
14
            throw new HeuristicCompletionException(HeuristicCompletionException.STATE_UNKNOWN, ex);
15
16
    }
事务回滚
事务执行中出现异常,需要回滚事务时,在TransactionAspectSupport中进行了catch操作。
1
    try {
2
                // This is an around advice: Invoke the next interceptor in the chain.
3
                // This will normally result in a target object being invoked.
4
                retVal = invocation.proceedWithInvocation();
5
            }
6
            catch (Throwable ex) {
7
                // target invocation exception
8
                completeTransactionAfterThrowing(txInfo, ex);
9
                throw ex;
10
            }
11
            finally {
12
                cleanupTransactionInfo(txInfo);
13
            }
最终还是Corbar进行操作
1
 @Override
2
    protected void doRollback(DefaultTransactionStatus defaultTransactionStatus) throws TransactionException {
3
        MultipleCauseException ex = new MultipleCauseException();
4
        List<TransactionStatus> statusList = (List<TransactionStatus>) defaultTransactionStatus.getTransaction();
5
        for (int i = transactionManagers.size() - 1; i >= 0; i--) {
6
            AbstractPlatformTransactionManager transactionManager = transactionManagers.get(i);
7
            TransactionStatus status = statusList.get(i);
8
            try {
9
                transactionManager.rollback(status);
10
            } catch (TransactionException e) {
11
                ex.add(e);
12
            }
13
        }
14
        if (!ex.getCauses().isEmpty())
15
            throw new UnexpectedRollbackException("one or more error on rolling back the transaction", ex);
16
    }
问题1
发现在提交和回滚操作中,如果数据操作突然断网,corbar存在多个数据源的时候,会造成事务不提交的bug。
问题2
在BestEffortMultiDataSourceTransactionManager的 dobegin方法中分别开启事务。
  @Override
    protected void doBegin(Object o, TransactionDefinition transactionDefinition) throws TransactionException {
        List<TransactionStatus> statusList = (List<TransactionStatus>) o;
        for (AbstractPlatformTransactionManager transactionManager : transactionManagers) {
            statusList.add(transactionManager.getTransaction(transactionDefinition));
        }
    }
假设存在两个managers, A  B,循环开启事务时, A正常开启事务,B开启事务时异常,此时抛出异常,不存在对A事务回滚的地方,会导致A库存在一条未提交事务而导致连接泄露问题。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值