spring事务的REQUIRES_NEW源码示例解析

 更新时间:2023年09月15日 08:49:26   作者:codecraft  
这篇文章主要为大家介绍了spring事务的REQUIRES_NEW源码示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

本文主要研究一下spring事务的REQUIRES_NEW

TransactionDefinition

org/springframework/transaction/TransactionDefinition.java

/**
     * Create a new transaction, suspending the current transaction if one exists.
     * Analogous to the EJB transaction attribute of the same name.
     * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
     * on all transaction managers. This in particular applies to
     * {@link org.springframework.transaction.jta.JtaTransactionManager},
     * which requires the {@code javax.transaction.TransactionManager} to be
     * made available it to it (which is server-specific in standard Java EE).
     * <p>A {@code PROPAGATION_REQUIRES_NEW} scope always defines its own
     * transaction synchronizations. Existing synchronizations will be suspended
     * and resumed appropriately.
     * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
     */
    int PROPAGATION_REQUIRES_NEW = 3;
PROPAGATION_REQUIRES_NEW在有事务的场景下会suspend当前事务,然后创建新事务

AbstractPlatformTransactionManager

org/springframework/transaction/support/AbstractPlatformTransactionManager.java

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
            if (debugEnabled) {
                logger.debug("Suspending current transaction, creating new transaction with name [" +
                        definition.getName() + "]");
            }
            SuspendedResourcesHolder suspendedResources = suspend(transaction);
            try {
                boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
                DefaultTransactionStatus status = newTransactionStatus(
                        definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
                doBegin(transaction, definition);
                prepareSynchronization(status, definition);
                return status;
            }
            catch (RuntimeException | Error beginEx) {
                resumeAfterBeginException(transaction, suspendedResources, beginEx);
                throw beginEx;
            }
        }
handleExistingTransaction方法在判断是PROPAGATION_REQUIRES_NEW,会执行suspend方法,然后newTransactionStatus,执行doBegin及prepareSynchronization

suspend

org/springframework/transaction/support/AbstractPlatformTransactionManager.java

/**
     * Suspend the given transaction. Suspends transaction synchronization first,
     * then delegates to the {@code doSuspend} template method.
     * @param transaction the current transaction object
     * (or {@code null} to just suspend active synchronizations, if any)
     * @return an object that holds suspended resources
     * (or {@code null} if neither transaction nor synchronization active)
     * @see #doSuspend
     * @see #resume
     */
    @Nullable
    protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
            try {
                Object suspendedResources = null;
                if (transaction != null) {
                    suspendedResources = doSuspend(transaction);
                }
                String name = TransactionSynchronizationManager.getCurrentTransactionName();
                TransactionSynchronizationManager.setCurrentTransactionName(null);
                boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
                TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
                Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
                TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
                boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
                TransactionSynchronizationManager.setActualTransactionActive(false);
                return new SuspendedResourcesHolder(
                        suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
            }
            catch (RuntimeException | Error ex) {
                // doSuspend failed - original transaction is still active...
                doResumeSynchronization(suspendedSynchronizations);
                throw ex;
            }
        }
        else if (transaction != null) {
            // Transaction active but no synchronization active.
            Object suspendedResources = doSuspend(transaction);
            return new SuspendedResourcesHolder(suspendedResources);
        }
        else {
            // Neither transaction nor synchronization active.
            return null;
        }
    }
suspend方法主要是执行doSuspendSynchronization方法返回suspendedSynchronizations,执行doSuspend返回suspendedResources,最后根据这两个创建SuspendedResourcesHolder

doSuspendSynchronization

/**
     * Suspend all current synchronizations and deactivate transaction
     * synchronization for the current thread.
     * @return the List of suspended TransactionSynchronization objects
     */
    private List<TransactionSynchronization> doSuspendSynchronization() {
        List<TransactionSynchronization> suspendedSynchronizations =
                TransactionSynchronizationManager.getSynchronizations();
        for (TransactionSynchronization synchronization : suspendedSynchronizations) {
            synchronization.suspend();
        }
        TransactionSynchronizationManager.clearSynchronization();
        return suspendedSynchronizations;
    }
doSuspendSynchronization这个遍历suspendedSynchronizations,挨个执行suspend,然后clearSynchronization

ResourceHolderSynchronization

org/springframework/transaction/support/ResourceHolderSynchronization.java

public void suspend() {
        if (this.holderActive) {
            TransactionSynchronizationManager.unbindResource(this.resourceKey);
        }
    }
ResourceHolderSynchronization的suspend执行的是TransactionSynchronizationManager.unbindResource

unbindResource

org/springframework/transaction/support/TransactionSynchronizationManager.java

/**
     * Unbind a resource for the given key from the current thread.
     * @param key the key to unbind (usually the resource factory)
     * @return the previously bound value (usually the active resource object)
     * @throws IllegalStateException if there is no value bound to the thread
     * @see ResourceTransactionManager#getResourceFactory()
     */
    public static Object unbindResource(Object key) throws IllegalStateException {
        Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
        Object value = doUnbindResource(actualKey);
        if (value == null) {
            throw new IllegalStateException(
                    "No value for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
        }
        return value;
    }
    /**
     * Actually remove the value of the resource that is bound for the given key.
     */
    @Nullable
    private static Object doUnbindResource(Object actualKey) {
        Map<Object, Object> map = resources.get();
        if (map == null) {
            return null;
        }
        Object value = map.remove(actualKey);
        // Remove entire ThreadLocal if empty...
        if (map.isEmpty()) {
            resources.remove();
        }
        // Transparently suppress a ResourceHolder that was marked as void...
        if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
            value = null;
        }
        if (value != null && logger.isTraceEnabled()) {
            logger.trace("Removed value [" + value + "] for key [" + actualKey + "] from thread [" +
                    Thread.currentThread().getName() + "]");
        }
        return value;
    }
unbindResource主要是执行doUnbindResource,从resources中移除

cleanupAfterCompletion

org/springframework/transaction/support/AbstractPlatformTransactionManager.java

/**
     * Clean up after completion, clearing synchronization if necessary,
     * and invoking doCleanupAfterCompletion.
     * @param status object representing the transaction
     * @see #doCleanupAfterCompletion
     */
    private void cleanupAfterCompletion(DefaultTransactionStatus status) {
        status.setCompleted();
        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());
        }
    }
在内嵌事务执行完之后,会判断是否有suspendedResources,如果有则执行resume,恢复之前suspend的事务

resume

org/springframework/transaction/support/AbstractPlatformTransactionManager.java

/**
     * Resume the given transaction. Delegates to the {@code doResume}
     * template method first, then resuming transaction synchronization.
     * @param transaction the current transaction object
     * @param resourcesHolder the object that holds suspended resources,
     * as returned by {@code suspend} (or {@code null} to just
     * resume synchronizations, if any)
     * @see #doResume
     * @see #suspend
     */
    protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)
            throws TransactionException {
        if (resourcesHolder != null) {
            Object suspendedResources = resourcesHolder.suspendedResources;
            if (suspendedResources != null) {
                doResume(transaction, suspendedResources);
            }
            List<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;
            if (suspendedSynchronizations != null) {
                TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive);
                TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);
                TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly);
                TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name);
                doResumeSynchronization(suspendedSynchronizations);
            }
        }
    }
resume方法执行doResume,然后恢复之前的TransactionSynchronizationManager的一些设置

doResume

org/springframework/orm/jpa/JpaTransactionManager.java

@Override
    protected void doResume(@Nullable Object transaction, Object suspendedResources) {
        SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
        TransactionSynchronizationManager.bindResource(
                obtainEntityManagerFactory(), resourcesHolder.getEntityManagerHolder());
        if (getDataSource() != null && resourcesHolder.getConnectionHolder() != null) {
            TransactionSynchronizationManager.bindResource(getDataSource(), resourcesHolder.getConnectionHolder());
        }
    }
doResume这里就是给bind回来

小结

spring事务的REQUIRES_NEW传播级别的实现就是对当前事务进行suspend,底层是unbind,然后创建新事务,执行完毕判断是否有suspend的事务,有则执行resume,底层是bind。具体对于mysql来讲,它不感知这些嵌套事务,它先接收到的是内嵌的新事务的sql,然后提交,最后接收到了外层resume回来的事务。

以上就是spring事务的REQUIRES_NEW的详细内容,更多关于spring事务REQUIRES_NEW的资料请关注脚本之家其它相关文章!

相关文章

  • 详解Java虚拟机(JVM)运行时

    详解Java虚拟机(JVM)运行时

    JVM(Java虚拟机)是一个抽象的计算模型。这篇文章主要介绍了Java虚拟机(JVM)运行时的相关知识,需要的朋友可以参考下
    2018-10-10
  • SpringBoot项目改为SpringCloud项目使用nacos作为注册中心的方法

    SpringBoot项目改为SpringCloud项目使用nacos作为注册中心的方法

    本文主要介绍了SpringBoot项目改为SpringCloud项目使用nacos作为注册中心,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • JpaRepository如何实现增删改查并进行单元测试

    JpaRepository如何实现增删改查并进行单元测试

    这篇文章主要介绍了JpaRepository如何实现增删改查并进行单元测试,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • 基于eclipse.ini内存设置的问题详解

    基于eclipse.ini内存设置的问题详解

    本篇文章是对eclipse.ini内存设置的问题进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • Mybatis sql与xml文件读取方法详细分析

    Mybatis sql与xml文件读取方法详细分析

    这篇文章主要介绍了Mybatis sql与xml文件读取方法,在执行一个自定义sql语句时,dao对应的代理对象时如何找到sql,也就是dao的代理对象和sql之间的关联关系是如何建立的
    2023-01-01
  • springcloud中RabbitMQ死信队列与延迟交换机实现方法

    springcloud中RabbitMQ死信队列与延迟交换机实现方法

    死信队列是消息队列中非常重要的概念,同时我们需要业务场景中都需要延迟发送的概念,比如12306中的30分钟后未支付订单取消,那么本期,我们就来讲解死信队列,以及如何通过延迟交换机来实现延迟发送的需求,感兴趣的朋友一起看看吧
    2022-05-05
  • 解决IDEA maven 项目修改代码不生效,mvn clean、install后才生效

    解决IDEA maven 项目修改代码不生效,mvn clean、install后才生效

    这篇文章主要介绍了解决IDEA maven 项目修改代码不生效,mvn clean、install后才生效的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • Java文件读取写入后 md5值不变的实现方法

    Java文件读取写入后 md5值不变的实现方法

    下面小编就为大家分享一篇Java文件读取写入后 md5值不变的实现方法,具有很好的参考价值,希望对大家有所帮助
    2017-11-11
  • Java实现文件及文件夹的删除

    Java实现文件及文件夹的删除

    这篇文章主要为大家详细介绍了Java实现文件及文件夹的删除,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • 详解Java爬虫利器Jsoup

    详解Java爬虫利器Jsoup

    Jsoup是一款Java语言开发的HTML解析器,用于解析HTML文档以及对HTML文档进行操作,处理等,本文就将详细给大家介绍一下Java中的爬虫利器Jsoup,感兴趣的同学可以参考一下
    2023-06-06

最新评论