spring--事务原理

Spring支持以下7种事务传播行为。


传播行为


XML文件

propagation


含义


PROPAGATION_REQUIRED


REQUIRED


表示当前方法必须在一个具有事务的上下文中运行。

如果当前没有事务,就新建一个事务;如果已经存在一个事务,就加入到这个事务中。

(如果被调用端发生调用端需要回滚的异常,那么调用端和被调用端事务都将回滚;如果被调用端异常不是调用端需要回滚的,那么调用端终止执行,已执行操作正常提交)


PROPAGATION_SUPPORTS


SUPPORTS


表示当前方法不必需要具有一个事务上下文。

如果当前没有事务,就以非事务方式执行;但是如果有一个事务的话,它就加入到这个事务中运行。


PROPAGATION_MANDATORY


MANDATORY


表示当前方法必须在一个事务中运行。

如果当前没有事务,就抛出异常;如果有事务,就加入到这个事务中。

PROPAGATION_REQUIRES_NEW REQUIRES_NEW
表示当前方法必须运行在它自己的事务中,新建事务,如果当前存在事务,把当前事务挂起,直到新的事务提交或者回滚才恢复执行。

(如果被调用端抛出rollback异常,则被调用端回滚,如果同时是调用端的rollback异常,调用端同时回滚)


PROPAGATION_NOT_SUPPORTED


NOT_SUPPORTED


表示该方法不应该在一个事务中运行,应该以非事务方式执行,每句sql马上提交。

如果当前存在事务,就把当前事务挂起。

(如果被调用端抛出调用端rollback异常,则调用端回滚)


PROPAGATION_NEVER


NEVER


表示当前方法不应该在一个事务中运行,应该以非事务方式执行。

如果存在一个事务,则抛出异常


PROPAGATION_NESTED


NESTED


如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作;如果当前有一个事务,则该方法应该运行在一个嵌套事务中,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。

(如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚;反之,内层事务并不影响外层事务,如果内层抛出异常不需rollback,则忽略,如果内层抛出异常需要rollback,则回滚到外层的savepoint)

spring中配置事务时,往往这样

<tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="do*" read-only="false" rollback-for="java.lang.Exception"/>
            <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
        </tx:attributes>
</tx:advice>

<aop:config>
        <aop:pointcut id="pc" expression="execution(* ffm.web.service.*.*(..))"/>
        <aop:advisor pointcut-ref="pc" advice-ref="txAdvice"/>
</aop:config>

但是是怎么起作用的呢?

tx是TransactionNameSpace,对应的是handler是TxNamespaceHandler,<tx:advice />最终解析出一个以TransactionInerceptor为classname的beandefinition并且注册这个bean,拦截方法如下:

public Object invoke(final MethodInvocation invocation) throws Throwable {
        Class targetClass = invocation.getThis() != null?AopUtils.getTargetClass(invocation.getThis()):null;
        return this.invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
            public Object proceedWithInvocation() throws Throwable {
                return invocation.proceed();
            }
        });
    }

1. 调用父类 TransactionAspectSupport的invokeWithinTransaction方法:

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final TransactionAspectSupport.InvocationCallback invocation) throws Throwable {        //事务隔离级别、事务传播策略、只读、回滚等属性信息
        final TransactionAttribute txAttr = this.getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
        final PlatformTransactionManager tm = this.determineTransactionManager(txAttr);
        final String joinpointIdentification = this.methodIdentification(method, targetClass);
        if(txAttr != null && tm instanceof CallbackPreferringPlatformTransactionManager) {
            try {
                Object ex1 = ((CallbackPreferringPlatformTransactionManager)tm).execute(txAttr, new TransactionCallback() {
                    public Object doInTransaction(TransactionStatus status) {
                        TransactionAspectSupport.TransactionInfo txInfo = TransactionAspectSupport.this.prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);

                        TransactionAspectSupport.ThrowableHolder var4;
                        try {
                            Object ex = invocation.proceedWithInvocation();
                            return ex;
                        } catch (Throwable var8) {
                            if(txAttr.rollbackOn(var8)) {
                                if(var8 instanceof RuntimeException) {
                                    throw (RuntimeException)var8;
                                }

                                throw new TransactionAspectSupport.ThrowableHolderException(var8);
                            }

                            var4 = new TransactionAspectSupport.ThrowableHolder(var8);
                        } finally {
                            TransactionAspectSupport.this.cleanupTransactionInfo(txInfo);
                        }

                        return var4;
                    }
                });
                if(ex1 instanceof TransactionAspectSupport.ThrowableHolder) {
                    throw ((TransactionAspectSupport.ThrowableHolder)ex1).getThrowable();
                } else {
                    return ex1;
                }
            } catch (TransactionAspectSupport.ThrowableHolderException var14) {
                throw var14.getCause();
            }
        } else {       // step 1.1
            TransactionAspectSupport.TransactionInfo ex = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
            Object retVal = null;

            try {
                retVal = invocation.proceedWithInvocation();
            } catch (Throwable var15) {
                this.completeTransactionAfterThrowing(ex, var15);
                throw var15;
            } finally {          // step 1.2
                this.cleanupTransactionInfo(ex);
            }

            this.commitTransactionAfterReturning(ex);
            return retVal;
        }
    }

1.1 关键方法createTransactionIfNecessary

protected TransactionAspectSupport.TransactionInfo createTransactionIfNecessary(PlatformTransactionManager tm, final TransactionAttribute txAttr, final String joinpointIdentification) {
        if(txAttr != null && ((TransactionAttribute)txAttr).getName() == null) {
            txAttr = new DelegatingTransactionAttribute((TransactionAttribute)txAttr) {
                public String getName() {
                    return joinpointIdentification;
                }
            };
        }

        TransactionStatus status = null;
        if(txAttr != null) {
            if(tm != null) {          //step 1.1.1 调用org.springframework.jdbc.datasource.DataSourceTransactionManager
                status = tm.getTransaction((TransactionDefinition)txAttr);
            } else if(this.logger.isDebugEnabled()) {
                this.logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured");
            }
        }
     //step 1.1.2绑定到当前线程
        return this.prepareTransactionInfo(tm, (TransactionAttribute)txAttr, joinpointIdentification, status);
    }

1.1.1 调用AbstractPlatformTransactionManager的getTransaction

public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {        //step 1.1.1.1
        Object transaction = this.doGetTransaction();
        boolean debugEnabled = this.logger.isDebugEnabled();
        if(definition == null) {
            definition = new DefaultTransactionDefinition();
        }
        //step 1.1.1.2
        if(this.isExistingTransaction(transaction)) {
            return this.handleExistingTransaction((TransactionDefinition)definition, transaction, debugEnabled);
        } else if(((TransactionDefinition)definition).getTimeout() < -1) {
            throw new InvalidTimeoutException("Invalid transaction timeout", ((TransactionDefinition)definition).getTimeout());
        } else if(((TransactionDefinition)definition).getPropagationBehavior() == 2) {
            throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation \‘mandatory\‘");
        } else if(((TransactionDefinition)definition).getPropagationBehavior() != 0 && ((TransactionDefinition)definition).getPropagationBehavior() != 3 && ((TransactionDefinition)definition).getPropagationBehavior() != 6) {
            boolean newSynchronization1 = this.getTransactionSynchronization() == 0;
            return this.prepareTransactionStatus((TransactionDefinition)definition, (Object)null, true, newSynchronization1, debugEnabled, (Object)null);
        } else {
            AbstractPlatformTransactionManager.SuspendedResourcesHolder newSynchronization = this.suspend((Object)null);
            if(debugEnabled) {
                this.logger.debug("Creating new transaction with name [" + ((TransactionDefinition)definition).getName() + "]: " + definition);
            }

            try {
                boolean err = this.getTransactionSynchronization() != 2;
                DefaultTransactionStatus status = this.newTransactionStatus((TransactionDefinition)definition, transaction, true, err, debugEnabled, newSynchronization);
                this.doBegin(transaction, (TransactionDefinition)definition);
                this.prepareSynchronization(status, (TransactionDefinition)definition);
                return status;
            } catch (RuntimeException var7) {
                this.resume((Object)null, newSynchronization);
                throw var7;
            } catch (Error var8) {
                this.resume((Object)null, newSynchronization);
                throw var8;
            }
        }
    }

1.1.1.1调用 DataSourceTransactionManager doGetTransaction方法

protected Object doGetTransaction() {
        DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject(null);
        txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
        ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.dataSource);
        txObject.setConnectionHolder(conHolder, false);
        return txObject;
    }

生成一个DataSourceTransactionObject 事物对象,设置它的ConnectionHolder为当前线程上绑定的key=this.dataSource的ConnectionHolder(当然有可能为空)

1.1.1.2开始处理这个新的 DataSourceTransactionObject 事物对象

DataSourceTransactionManager 的isExistingTransaction方法:

protected boolean isExistingTransaction(Object transaction) {
        DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)transaction;
        return txObject.getConnectionHolder() != null && txObject.getConnectionHolder().isTransactionActive();
    }

如果返回true,

private TransactionStatus handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException {
        if(definition.getPropagationBehavior() == 5) {
            throw new IllegalTransactionStateException("Existing transaction found for transaction marked with propagation \‘never\‘");
        } else {
            AbstractPlatformTransactionManager.SuspendedResourcesHolder newSynchronization3;
            boolean isoConstants2;
            if(definition.getPropagationBehavior() == 4) {
                if(debugEnabled) {
                    this.logger.debug("Suspending current transaction");
                }

                newSynchronization3 = this.suspend(transaction);
                isoConstants2 = this.getTransactionSynchronization() == 0;
                return this.prepareTransactionStatus(definition, (Object)null, false, isoConstants2, debugEnabled, newSynchronization3);
            } else if(definition.getPropagationBehavior() == 3) {
                if(debugEnabled) {
                    this.logger.debug("Suspending current transaction, creating new transaction with name [" + definition.getName() + "]");
                }

                newSynchronization3 = this.suspend(transaction);

                try {
                    isoConstants2 = this.getTransactionSynchronization() != 2;
                    DefaultTransactionStatus status = this.newTransactionStatus(definition, transaction, true, isoConstants2, debugEnabled, newSynchronization3);
                    this.doBegin(transaction, definition);
                    this.prepareSynchronization(status, definition);
                    return status;
                } catch (RuntimeException var7) {
                    this.resumeAfterBeginException(transaction, newSynchronization3, var7);
                    throw var7;
                } catch (Error var8) {
                    this.resumeAfterBeginException(transaction, newSynchronization3, var8);
                    throw var8;
                }
            } else {
                boolean newSynchronization1;
                if(definition.getPropagationBehavior() == 6) {
                    if(!this.isNestedTransactionAllowed()) {
                        throw new NestedTransactionNotSupportedException("Transaction manager does not allow nested transactions by default - specify \‘nestedTransactionAllowed\‘ property with value \‘true\‘");
                    } else {
                        if(debugEnabled) {
                            this.logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
                        }

                        if(this.useSavepointForNestedTransaction()) {
                            DefaultTransactionStatus newSynchronization2 = this.prepareTransactionStatus(definition, transaction, false, false, debugEnabled, (Object)null);
                            newSynchronization2.createAndHoldSavepoint();
                            return newSynchronization2;
                        } else {
                            newSynchronization1 = this.getTransactionSynchronization() != 2;
                            DefaultTransactionStatus isoConstants1 = this.newTransactionStatus(definition, transaction, true, newSynchronization1, debugEnabled, (Object)null);
                            this.doBegin(transaction, definition);
                            this.prepareSynchronization(isoConstants1, definition);
                            return isoConstants1;
                        }
                    }
                } else {
                    if(debugEnabled) {
                        this.logger.debug("Participating in existing transaction");
                    }

                    if(this.isValidateExistingTransaction()) {
                        if(definition.getIsolationLevel() != -1) {
                            Integer newSynchronization = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
                            if(newSynchronization == null || newSynchronization.intValue() != definition.getIsolationLevel()) {
                                Constants isoConstants = DefaultTransactionDefinition.constants;
                                throw new IllegalTransactionStateException("Participating transaction with definition [" + definition + "] specifies isolation level which is incompatible with existing transaction: " + (newSynchronization != null?isoConstants.toCode(newSynchronization, "ISOLATION_"):"(unknown)"));
                            }
                        }

                        if(!definition.isReadOnly() && TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
                            throw new IllegalTransactionStateException("Participating transaction with definition [" + definition + "] is not marked as read-only but existing transaction is");
                        }
                    }

                    newSynchronization1 = this.getTransactionSynchronization() != 2;
                    return this.prepareTransactionStatus(definition, transaction, false, newSynchronization1, debugEnabled, (Object)null);
                }
            }
        }
    }

初始下这个返回false,走下面的判断,根据传播机制

最后一个else有个关键方法doBegin,DataSourceTransactionManager 实现了这个抽象方法

protected void doBegin(Object transaction, TransactionDefinition definition) {
        DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)transaction;
        Connection con = null;

        try {
            if(txObject.getConnectionHolder() == null || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
                Connection ex = this.dataSource.getConnection();
                if(this.logger.isDebugEnabled()) {
                    this.logger.debug("Acquired Connection [" + ex + "] for JDBC transaction");
                }

                txObject.setConnectionHolder(new ConnectionHolder(ex), true);
            }

            txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
            con = txObject.getConnectionHolder().getConnection();
            Integer ex1 = DataSourceUtils.prepareConnectionForTransaction(con, definition);
            txObject.setPreviousIsolationLevel(ex1);
            if(con.getAutoCommit()) {
                txObject.setMustRestoreAutoCommit(true);
                if(this.logger.isDebugEnabled()) {
                    this.logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
                }

                con.setAutoCommit(false);
            }

            txObject.getConnectionHolder().setTransactionActive(true);
            int timeout = this.determineTimeout(definition);
            if(timeout != -1) {
                txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
            }

            if(txObject.isNewConnectionHolder()) {
                TransactionSynchronizationManager.bindResource(this.getDataSource(), txObject.getConnectionHolder());
            }

        } catch (Throwable var7) {
            if(txObject.isNewConnectionHolder()) {
                DataSourceUtils.releaseConnection(con, this.dataSource);
                txObject.setConnectionHolder((ConnectionHolder)null, false);
            }

            throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", var7);
        }
    }

可以看出,这里给DataSourceTransactionObject 事物对象设置它的ConnectionHolder,真正打开连接激活事务,并把这个ConnectionHolder绑定在当前线程上(key=this.dataSource)

1.1.2 生成一个TransactionInfo,设置TransactionStatus为上一步1.1.1得到的TransactionStatus,并把自己绑定 到当前线程

protected TransactionAspectSupport.TransactionInfo prepareTransactionInfo(PlatformTransactionManager tm, TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {
        TransactionAspectSupport.TransactionInfo txInfo = new TransactionAspectSupport.TransactionInfo(tm, txAttr, joinpointIdentification);
        if(txAttr != null) {
            if(this.logger.isTraceEnabled()) {
                this.logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
            }

            txInfo.newTransactionStatus(status);
        } else if(this.logger.isTraceEnabled()) {
            this.logger.trace("Don\‘t need to create transaction for [" + joinpointIdentification + "]: This method isn\‘t transactional.");
        }

        txInfo.bindToThread();
        return txInfo;
    }
TransactionInfo的bindToThread方法:
private void bindToThread() {
            this.oldTransactionInfo = (TransactionAspectSupport.TransactionInfo)TransactionAspectSupport.transactionInfoHolder.get();
            TransactionAspectSupport.transactionInfoHolder.set(this);
        }

1.2 重置当前线程的TransactionInfo为oldTransactionInfo

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

以常用的propagation="SUPPORTS" / "REQUIRED"为例,分析跟踪事务的过程

  • SUPPORTS->REQUIRED,`一路到1.1.1.2,isExistingTransaction返回false,进入
if(((TransactionDefinition)definition).getPropagationBehavior() != 0 && ((TransactionDefinition)definition).getPropagationBehavior() != 3 && ((TransactionDefinition)definition).getPropagationBehavior() != 6) {
            boolean newSynchronization1 = this.getTransactionSynchronization() == 0;
            return this.prepareTransactionStatus((TransactionDefinition)definition, (Object)null, true, newSynchronization1, debugEnabled, (Object)null);

以非事务方式运行,接着调用REQUIRED的方法,直到1.1.1.2,isExistingTransaction返回false,进入最后一个else,打开新事务

  • REQUIRED->SUPPORTS,到1.1.1.2时,isExistingTransaction返回false,进入最后一个else,打开新事务。接着调用SUPPORTS的方法,到达1.1.1.2时发现有事务,进入handleExistingTransaction处理,最终加入已有事务

参考文章:

1. 揭开Spring事务处理

2. Spring中的事务控制学习中(转)

3. Spring 事务管理高级应用难点剖析--转

4. spring源码分析之——spring 事务管理实现方式

5. Spring @Transactional 如何开启事务

6. 详解spring事务属性

7. Spring事务处理的实现

8. spring事务传播机制实例讲解

时间: 2024-12-05 11:42:42

spring--事务原理的相关文章

深入理解 Spring 事务原理

一.事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的.对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行: 获取连接 Connection con = DriverManager.getConnection() 开启事务con.setAutoCommit(true/false); 执行CRUD 提交事务/回滚事务 con.commit() / con.rollback(); 关闭连接 conn.close(); 使

一文带你深入浅出Spring 事务原理

Spring事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的.对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行: 获取连接 Connection con = DriverManager.getConnection() 开启事务con.setAutoCommit(true/false); 执行CRUD 提交事务/回滚事务 con.commit() / con.rollback(); 关闭连接 conn.close(

mybatis源码分析(四) mybatis与spring事务管理分析

mybatis源码分析(四) mybatis与spring事务管理分析 一丶从jdbc的角度理解什么是事务 从mysql获取一个连接之后, 默认是自动提交, 即执行完sql之后, 就会提交事务. 这种事务的范围是一条sql语句. 将该连接设置非自动提交, 可以执行多条sql语句, 然后由程序决定是提交事务, 还是回滚事务. 这也是我们常说的事务. Connection connection = dataSource.getConnection(); // connection.setTransa

Spring 事务管理原理探究

此处先粘贴出Spring事务需要的配置内容: 1.Spring事务管理器的配置文件: <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" />..... <

spring事务的原理

spring事务管理的本质是通过aop为目标类生成动态代理类,并在需要进行事务管理的方法中加入事务管理的横切逻辑代码 https://juejin.im/entry/5836572767f3560065f1939b

Spring事务管理实现原理及MySQL InnoBD引擎行锁概述

Spring实现事务管理的机制 Spring事务管理是基于AOP编程思想实现,Spring框架被广泛使用的原因之一,就是提供了强大的事务管理机制. AOP是什么?我们常说的AOP并不是指一种开发技术,而是一种编程思想,AOP的核心概念就是面向切面编程,实现可插拔,降低程序之前的耦合性,提高重用性. Spring AOP 基于动态代理实现,一种是JDK动态代理,另一种是CGLIB动态代理. spring2.5之前声明式事务可以这样实现: ?<!-- 声明使用的spring事务管理器--> <

spring实现事务原理

spring事务实现主要有两种方法 1.编程式,beginTransaction().commit().rollback()等事务管理相关的方法 2.声明式,利用注解Transactional 或者aop配置 xml配置如下所示 1 <!-- 事务管理器 --> 2 3 <bean id="myTracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransacti

Spring事务管理源码分析

Spring事务管理方式 依据Spring.xsd文件可以发现,Spring提供了advice,annotation-driven,jta-transaction-manager3种事务管理方式.详情可查看相应版本xsd文件.这里参照的版本是3.2.我们也只分析advice方式的源码,期望以此为突破口了解Spring事务管理的原理. Advice事务管理 XSD文件 我们先来看下xsd文件的配置 <xsd:element name="advice"> <xsd:com

Spring事务管理--多个ORM框架在使用时的情况分析

公司的项目已经接近尾声了,总结一下项目中用到的技术,我发现项目中的有些东西还是挺模糊的,只是知道这么用就行了.并不清楚其中的原理.由于公司的项目比较老,是7年前的一个项目了,中间一直有人在维护,也是在这个过程中不断融入了新的东西,比如就项目的持久化这块来说,就用了ibatis.mybatis.hibernate.spring JDBC四种混合的框架.究其原因只能说是历史遗留问题,就不做过多的解释了.但是这么多持久化的框架如何协同工作的,尤其是事务的控制,一个系统中使用如此多的持久化框架是,他们是

详细介绍Spring事务管理

在学习spring事务管理时,我忍不住要问,spring为什么进行事务管理,spring怎么进行的事务管理?首先,为什么要进行事务,接下来说说spring是怎样进行事务管理的. 我们都知道spring提供两种管理事务的方式,一种是声明式事务,一种是编程式事务. Spring的声明式事务管理,基于Spring的AOP,不再需要不停地写commit,rollback,(但Spring仍然没有放弃编程式的事务管理策略). Spring的编程式事务管理,为我们提供了一个TransactionTempla