在Spring中,声明式事务是通过事务属性(transaction attribute)来定义的。事务属性描述了事务策略如何应用到方法上。事务属性包含5个方面:
 
传播行为
 
隔离级别
 
是否只读
 
事务超时
 
回滚规则
 
尽管Spring提供了多种声明式事务的机制,但是所有的方式都依赖这五个参数来控制如何管理事务策略。
(上述内容参考《Spring In Action》第三版)。
 
对于声明式事务是使用Spring提供的tx配置命名空间。其中一些声明式事务配置元素依赖于部分Spring的AOP配置元素。
下面是一个具体配置的例子:
<tx:advice id="txAdviceHibernate" transaction-manager="txManagerHibernate">  

        <tx:attributes>  

            <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" no-rollback-for="" />         

            <tx:method name="batch*" propagation="REQUIRED" rollback-for="Exception" />  

            <tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception" />  

            <tx:method name="execute*" propagation="REQUIRED" rollback-for="Exception" />  

            <tx:method name="export*" propagation="REQUIRED" rollback-for="Exception" />  

            <tx:method name="import*" propagation="REQUIRED" rollback-for="Exception" />  

            <tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception" />  

            <tx:method name="save*" propagation="REQUIRED" rollback-for="Exception" />  

            <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception" />  

            <tx:method name="count*" propagation="NOT_SUPPORTED" read-only="true" />  

            <tx:method name="find*" propagation="NOT_SUPPORTED" read-only="true" />  

            <tx:method name="get*" propagation="NOT_SUPPORTED" read-only="true" />  

            <tx:method name="list*" propagation="NOT_SUPPORTED" read-only="true" />  

            <tx:method name="load*" propagation="NOT_SUPPORTED" read-only="true" />  

            <tx:method name="page*" propagation="NOT_SUPPORTED" read-only="true" />  

            <tx:method name="query*" propagation="NOT_SUPPORTED" read-only="true" />  

        </tx:attributes>  

</tx:advice>  

<!--此处应想办法实现动态加载-->  

<aop:config>   

	<aop:advisor pointcut="execution(* com.cetc.datamc.app.collect.bs.*.*(..)) 

		or execution(* com.cetc.datamc.app.mdms.bs.*.*(..))" advice-ref="txAdviceHibernate" />   

</aop:config>

  其中<tx:advice>是用来声明事务性策略的。对于<tx:advice>来说,事务属性定义在<tx:attributes>元素中,该元素包含了一个或多个的<tx:method>元素。<tx:method>元素为某个(或某些)name属性(使用通配符)指定的方法定义事务的参数。

当使用<tx:advice>来声明事务时,你还需要一个事务管理器,就像使用TransactionProxyFactoryBean那样。根据约定优于配置,<tx:advice>假定事务管理器被声明为一个id为transactionManager的Bean。如果碰巧为事务管理器配置了一个不同的id(如txManager),则需要在transaction-manager属性中明确指定事务管理器的id:

    <tx:advice id="txAdviceHibernate" transaction-manager="txManager">  

        ...

    </tx:advice>
<tx:advice>只是定义了AOP通知,用于把事务边界通知给方法。但是这只是事务通知,而不是完整的事务性切面。我们在<tx:advice>中没有声明哪些Bean应该被通知——我们需要一个切点来做这件事。为了完整定义事务性切面,我们必须定义一个通知器(advisor)。这就涉及aop命名空间了。通过上面的配置示例可以看到:
 
这里的pointcut属性使用了AspectJ切入点表达式来表明通知器适用于com.cetc.datamc.app.collect.bs和com.cetc.datamc.app.mdms.bs包下的所有类的所有方法。哪些方法应该真正运行在事务中以及方法的事务属性都是由这个事务通知来定义的。而事务通知是advice-ref属性来指定的,它引用了名为txAdviceHibernate的通知。
 
在这里有一点需要注意的是对于切面的织入,不是说只有在<tx:method>中配置的方法才会被织入切面。根据切面的原理,是在pointcut中配置的符合条件的目标对象都会被织入切面。Spring中是基于动态代理的方式来实现切面的,所以Spring中的切面是由包裹了目标对象的代理类实现。代理类处理方法的调用,执行额外的切面逻辑。直到应用需要被代理的Bean时,Spring才创建代理对象。如果使用的是ApplicationContext,在ApplicationContext从BeanFactory中加载所有Bean时,Spring创建被代理的对象。这时候,所有符合在pointcut中配置的类的相关方法就会被织入切面代码,并且返回相关的动态代理对象。所以说不管有没有在<tx:method>中配置相关方法,只要符合pointcut中的条件,方法就会被织入切面代码。
 
因此,在上面的例子中,所有的com.cetc.datamc.app.collect.bs和com.cetc.datamc.app.mdms.bs包中所有类的所有方法都会被织入事务管理的相关切面代码。
 
在创建好动态代理后,之前所有依赖注入的相关接口的实现类就会替换为创建的动态代理类。这样程序在使用接口调用时,就会调用到织入切面代码的动态代理类实现。
 
因此,在使用声明式事务的时候也需要注意,所有需要管理事务的类必须通过spring context管理,直接new的对象不行。 所有需要事务管理的类必须使用interface,这样动态代理才有用。
 
例如假设在com.cetc.datamc.app.collect.bs包中有下面的类
public interface IDataCollect {

    public String addDataItem(String data);

} 

public class DataCollectService implements IDataCollect { 

    private IMetadataService metaService;

    public void setMetaService(IMetadataService metaService) {

        this.metaService = metaService;

    }

    public String addDataItem(String data) {

        metaService.deleteMeta(data);

        return metaService.addMeta(data);

    }

}

public interface IMetadataService {

    public void deleteMeta(String data);

    public String addMeta(String data);

    public String queryMetaId(String data);

} 

public class MetadataService implements IMetadataService {

    public void deleteMeta(String data) {

        System.out.println("delete metadata");

    }

    public String addMeta(String data) {

        System.out.println("add metadata");

        String id = queryMetaId(data);

        return data;

    }

    public String queryMetaId(String data) {

        return "id";

    }

}

这样,在DataCollectService中有一个IMetadataService类型的对象。那么在实际中该类型则是被Spring替换为动态代理对象,而不是原来的MetaService对象。所以调用了IMetadataService中的deleteMeta和addMeta方法,这两个方法都是调用的织入事务切面代码的函数。而不是原来的deleteMeta和addMeta方法。

另外在MetaService还可以看到addMeta中调用了queryMetaId方法。这个方法调用的就是没有织入切面代码的原来的函数。因为这个不是使用接口调用的,而是直接调用的对象本身的方法。所以就是该对象原来的queryMetaId方法。这就是为什么需要事务管理的类必须使用interface

事务管理的切面属于<aop:around>(AOP环绕通知)类型的切面。

org.springframework.transaction.interceptor.TransactionAspectSupport类

/**

     * General delegate for around-advice-based subclasses, delegating to several other template

     * methods on this class. Able to handle {@link CallbackPreferringPlatformTransactionManager}

     * as well as regular {@link PlatformTransactionManager} implementations.

     * @param method the Method being invoked

     * @param targetClass the target class that we're invoking the method on

     * @param invocation the callback to use for proceeding with the target invocation

     * @return the return value of the method, if any

     * @throws Throwable propagated from the target invocation

     */

    protected Object invokeWithinTransaction(Method method, Class targetClass, 

                        final InvocationCallback invocation)

            throws Throwable {

        // If the transaction attribute is null, the method is non-transactional.

        //这里返回的即是在tx:method中配置的属性值

        //包括propagation, isolation, readonly, timeout, readonly等属性的配置值。

        //如果一个方法没有在tx:method中配置,那么txAttr为null

        final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);

        final PlatformTransactionManager tm = determineTransactionManager(txAttr);

        final String joinpointIdentification = methodIdentification(method, targetClass);

        if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {

            // Standard transaction demarcation with getTransaction and commit/rollback calls.

            //该方法主要就是根据配置来采取合适的事务策略。

            //理解了该方法的调用原理,基本上spring的配置事务的各属性的涵义也就理解了

            TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

            Object retVal = null;

            try {

                // This is an around advice: Invoke the next interceptor in the chain.

                // This will normally result in a target object being invoked.

                retVal = invocation.proceedWithInvocation();

            }

            catch (Throwable ex) {

                // target invocation exception

                completeTransactionAfterThrowing(txInfo, ex);

                throw ex;

            }

            finally {

                cleanupTransactionInfo(txInfo);

            }

            commitTransactionAfterReturning(txInfo);

            return retVal;

        }

        else {

            // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.

            try {

                Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,

                        new TransactionCallback<Object>() {

                            public Object doInTransaction(TransactionStatus status) {

                                TransactionInfo txInfo = prepareTransactionInfo(

                                                    tm, txAttr, joinpointIdentification, status);

                                try {

                                    return invocation.proceedWithInvocation();

                                }

                                catch (Throwable ex) {

                                    if (txAttr.rollbackOn(ex)) {

                                        // A RuntimeException: will lead to a rollback.

                                        if (ex instanceof RuntimeException) {

                                            throw (RuntimeException) ex;

                                        }

                                        else {

                                            throw new ThrowableHolderException(ex);

                                        }

                                    }

                                    else {

                                        // A normal return value: will lead to a commit.

                                        return new ThrowableHolder(ex);

                                    }

                                }

                                finally {

                                    cleanupTransactionInfo(txInfo);

                                }

                            }

                        });

                // Check result: It might indicate a Throwable to rethrow.

                if (result instanceof ThrowableHolder) {

                    throw ((ThrowableHolder) result).getThrowable();

                }

                else {

                    return result;

                }

            }

            catch (ThrowableHolderException ex) {

                throw ex.getCause();

            }

        }

    }
/**

     * Create a transaction if necessary based on the given TransactionAttribute.

     * <p>Allows callers to perform custom TransactionAttribute lookups through

     * the TransactionAttributeSource.

     * @param txAttr the TransactionAttribute (may be {@code null})

     * @param joinpointIdentification the fully qualified method name

     * (used for monitoring and logging purposes)

     * @return a TransactionInfo object, whether or not a transaction was created.

     * The {@code hasTransaction()} method on TransactionInfo can be used to

     * tell if there was a transaction created.

     * @see #getTransactionAttributeSource()

     */

    @SuppressWarnings("serial")

    protected TransactionInfo createTransactionIfNecessary(

            PlatformTransactionManager tm, 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");

                }

            }

        }

        //如果没有在tx:method中配置,那么txAttr=null, 这样返回的TransactionStatus也为null

        return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);

    }

org.springframework.transaction.support.AbstractPlatformTransactionManager类

/**

     * This implementation handles propagation behavior. Delegates to

     * {@code doGetTransaction}, {@code isExistingTransaction}

     * and {@code doBegin}.

     * @see #doGetTransaction

     * @see #isExistingTransaction

     * @see #doBegin

     */

    public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {

        //doGetTransaction在各继承该类的子类中实现。

        //这里假设使用的是Hibernate的事务,那么实现类是HibernateTransactionManager类

        //这里的object即表示我们通常所说的Transaction,即事务的类的定义

        //对于Hibernate Transaction的具体类是HibernateTransactionObject 

        Object transaction = doGetTransaction();

        // Cache debug flag to avoid repeated checks.

        boolean debugEnabled = logger.isDebugEnabled();

        if (definition == null) {

            // Use defaults if no transaction definition given.

            definition = new DefaultTransactionDefinition();

        }

        //根据得到的transaction对象判断是否当前已经存在事务

        //如果存在事务,那么调用handleExistingTransaction来根据配置的策略处理事务

        if (isExistingTransaction(transaction)) {

            // Existing transaction found -> check propagation behavior to find out how to behave.

            return handleExistingTransaction(definition, transaction, debugEnabled);

        }

        // Check definition settings for new transaction.

        if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {

            throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());

        }

        //如果当前不存在事务,那么根据不同的策略配置来产生具体的事务行为。

        //这里即是各种不同配置策略行为的具体代码实现过程

        // No existing transaction found -> check propagation behavior to find out how to proceed.

        if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {

            throw new IllegalTransactionStateException(

                    "No existing transaction found for transaction marked with propagation 'mandatory'");

        }

        else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||

                definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||

            definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {

            SuspendedResourcesHolder suspendedResources = suspend(null);

            if (debugEnabled) {

                logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);

            }

            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 ex) {

                resume(null, suspendedResources);

                throw ex;

            }

            catch (Error err) {

                resume(null, suspendedResources);

                throw err;

            }

        }

        else {

            // Create "empty" transaction: no actual transaction, but potentially synchronization.

            boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);

            return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);

        }

    }

下面我们暂时先抛开如何doGetTransaction以及如何判断isExistingTransaction不谈,先来看看如何doBegin一个新事务。

在org.springframework.orm.hibernate3.HibernateTransactionManager类中的doBegin实现如下:

@Override

    protected void doBegin(Object transaction, TransactionDefinition definition) {

        HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;

        if (txObject.hasConnectionHolder() && !txObject.getConnectionHolder().isSynchronizedWithTransaction()) {

            throw new IllegalTransactionStateException(

                    "Pre-bound JDBC Connection found! HibernateTransactionManager does not support " +

                    "running within DataSourceTransactionManager if told to manage the DataSource itself. " +

                    "It is recommended to use a single HibernateTransactionManager for all transactions " +

                    "on a single DataSource, no matter whether Hibernate or JDBC access.");

        }

        Session session = null;

        try {

            //如果当前txObject没有已有的Session,那么打开一个新的Session.

            //txObject也可能已经有了Session,

            //例如如果配置了OpenSessionInViewFilter,且当前的线程是一个request线程,

            //那么就会在每个request线程中就先openSession,并且绑定到当前线程中。

            //这样在doGetTransaction就会获取到该Session。详见doGetTransaction函数和OpenSessionInViewFilter实现

            if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {

                Interceptor entityInterceptor = getEntityInterceptor();

                //这里是openSession,而不是getCurrentSession

                Session newSession = (entityInterceptor != null ?

                        getSessionFactory().openSession(entityInterceptor) : getSessionFactory().openSession());

                if (logger.isDebugEnabled()) {

                    logger.debug("Opened new Session [" + SessionFactoryUtils.toString(newSession) +

                            "] for Hibernate transaction");

                }

                //设置newSessionHolder和newSession状态为true

                txObject.setSession(newSession);

            }

            session = txObject.getSessionHolder().getSession();

            if (this.prepareConnection && isSameConnectionForEntireSession(session)) {

                // We're allowed to change the transaction settings of the JDBC Connection.

                if (logger.isDebugEnabled()) {

                    logger.debug(

                            "Preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");

                }

                Connection con = session.connection();

                Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);

                txObject.setPreviousIsolationLevel(previousIsolationLevel);

            }

            else {

                // Not allowed to change the transaction settings of the JDBC Connection.

                if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {

                    // We should set a specific isolation level but are not allowed to...

                    throw new InvalidIsolationLevelException(

                            "HibernateTransactionManager is not allowed to support custom isolation levels: " +

                            "make sure that its 'prepareConnection' flag is on (the default) and that the " +

                            "Hibernate connection release mode is set to 'on_close' (SpringTransactionFactory's default). " +

                            "Make sure that your LocalSessionFactoryBean actually uses SpringTransactionFactory: Your " +

                            "Hibernate properties should *not* include a 'hibernate.transaction.factory_class' property!");

                }

                if (logger.isDebugEnabled()) {

                    logger.debug(

                            "Not preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");

                }

            }

            //如果是一个new Session并且事务是只读的,则设置该Session flushMode为FlushMode.MANUAL

            if (definition.isReadOnly() && txObject.isNewSession()) {

                // Just set to MANUAL in case of a new Session for this transaction.

                session.setFlushMode(FlushMode.MANUAL);

            }

            //如果事务不是只读的,且已有一个Session时,重新设置该Session的flushMode

            if (!definition.isReadOnly() && !txObject.isNewSession()) {

                // We need AUTO or COMMIT for a non-read-only transaction.

                FlushMode flushMode = session.getFlushMode();

                if (flushMode.lessThan(FlushMode.COMMIT)) {

                    session.setFlushMode(FlushMode.AUTO);

                    txObject.getSessionHolder().setPreviousFlushMode(flushMode);

                }

            }

            Transaction hibTx;

            //设置timeout 然后beginTransaction

            // Register transaction timeout.

            int timeout = determineTimeout(definition);

            if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {

                // Use Hibernate's own transaction timeout mechanism on Hibernate 3.1+

                // Applies to all statements, also to inserts, updates and deletes!

                hibTx = session.getTransaction();

                hibTx.setTimeout(timeout);

                hibTx.begin();

            }

            else {

                // Open a plain Hibernate transaction without specified timeout.

                hibTx = session.beginTransaction();

            }

            // Add the Hibernate transaction to the session holder.

            txObject.getSessionHolder().setTransaction(hibTx);

            // Register the Hibernate Session's JDBC Connection for the DataSource, if set.

            if (getDataSource() != null) {

                Connection con = session.connection();

                ConnectionHolder conHolder = new ConnectionHolder(con);

                if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {

                    conHolder.setTimeoutInSeconds(timeout);

                }

                if (logger.isDebugEnabled()) {

                    logger.debug("Exposing Hibernate transaction as JDBC transaction [" + con + "]");

                }

                //将当前的conHolder绑定到线程上,可以用来判断当前线程是否已有事务

                TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);

                txObject.setConnectionHolder(conHolder);

            }

            // Bind the session holder to the thread.

            if (txObject.isNewSessionHolder()) {

                //将当前的SessionHolder绑定到当前线程上,可以用来判断当前线程是否已有事务

                TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());

            }

            txObject.getSessionHolder().setSynchronizedWithTransaction(true);

        }

        catch (Throwable ex) {

            if (txObject.isNewSession()) {

                try {

                    if (session.getTransaction().isActive()) {

                        session.getTransaction().rollback();

                    }

                }

                catch (Throwable ex2) {

                    logger.debug("Could not rollback Session after failed transaction begin", ex);

                }

                finally {

                    SessionFactoryUtils.closeSession(session);

                    txObject.setSessionHolder(null);

                }

            }

            throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);

        }

    }

好了,知道了doBegin函数的实现原理,让我们回过头来看doGetTransaction和isExistingTransaction函数的实现。这样就很容易理解了。

@Override

    protected Object doGetTransaction() {

        HibernateTransactionObject txObject = new HibernateTransactionObject();

        txObject.setSavepointAllowed(isNestedTransactionAllowed());

        //获取当前线程中是否已经有已绑定的SessionHolder。如果当前线程已经存在事务,那么就会存在SessionHolder

        //具体可见doBegin函数的实现

        SessionHolder sessionHolder =

                (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());

        if (sessionHolder != null) {

            if (logger.isDebugEnabled()) {

                logger.debug("Found thread-bound Session [" +

                        SessionFactoryUtils.toString(sessionHolder.getSession()) + "] for Hibernate transaction");

            }

            //如果已经有了SessionHolder,那么直接就把当前已有的SessionHolder赋给新的transaction Object

            txObject.setSessionHolder(sessionHolder);

        }

        else if (this.hibernateManagedSession) {

            try {

                //当前线程中已经绑定了session,例如openSessionInViewFilter的情况

                Session session = getSessionFactory().getCurrentSession();

                if (logger.isDebugEnabled()) {

                    logger.debug("Found Hibernate-managed Session [" +

                            SessionFactoryUtils.toString(session) + "] for Spring-managed transaction");

                }

                txObject.setExistingSession(session);

            }

            catch (HibernateException ex) {

                throw new DataAccessResourceFailureException(

                        "Could not obtain Hibernate-managed Session for Spring-managed transaction", ex);

            }

        }

        //如果当前线程已经绑定了ConnectionHolder,如果当前线程中已经开启了事务,就会存在ConnectionHolder

        //直接将已有的ConnectionHolder赋值给该transaction

        if (getDataSource() != null) {

            ConnectionHolder conHolder = (ConnectionHolder)

                    TransactionSynchronizationManager.getResource(getDataSource());

            txObject.setConnectionHolder(conHolder);

        }

        return txObject;

    }
@Override

protected boolean isExistingTransaction(Object transaction) {

    HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;

    //spring管理的事务或者是Hibernate自己管理的事务

    return (txObject.hasSpringManagedTransaction() ||

            (this.hibernateManagedSession && txObject.hasHibernateManagedTransaction()));

}

isExistingTransaction函数里面的的hasSpringManagedTransaction的实现如下:

public boolean hasSpringManagedTransaction() {

            //如果当前的transaction Object的sessionHolder不为null,说明当前存在事务

            return (this.sessionHolder != null && this.sessionHolder.getTransaction() != null);

        }

这两个函数都很简单,结合doGetTransaction函数的实现原理,就很容易理解了。

好了,最后再来看一下AbstractPlatformTransactionManager类中的AbstractPlatformTransactionManager函数的实现原理。这个函数也是主要根据不同的配置策略产生不同的事务行为。理解了该函数,也能对事务不同策略的配置理解的更加透彻了。

/**

     * Create a TransactionStatus for an existing transaction.

     */

    private TransactionStatus handleExistingTransaction(

            TransactionDefinition definition, Object transaction, boolean debugEnabled)

            throws TransactionException {

        //配置的策略为当前方法不应该运行在事务上下文中,如果当前正有一个事务运行,则会抛出异常

        if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {

            throw new IllegalTransactionStateException(

                    "Existing transaction found for transaction marked with propagation 'never'");

        }

        //配置的策略为当前方法不应该运行在事务中,如果存在当前事务,在该方法运行期间,当前事务将被挂起

        if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {

            if (debugEnabled) {

                logger.debug("Suspending current transaction");

            }

            Object suspendedResources = suspend(transaction);

            boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);

            return prepareTransactionStatus(

                    definition, null, false, newSynchronization, debugEnabled, suspendedResources);

        }

        //配置的策略为当前方法必须运行在它自己的事务中,一个新的事务将被启动。

        //如果存在当前事务,在该方法运行期间,当前事务将被挂起

        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 beginEx) {

                resumeAfterBeginException(transaction, suspendedResources, beginEx);

                throw beginEx;

            }

            catch (Error beginErr) {

                resumeAfterBeginException(transaction, suspendedResources, beginErr);

                throw beginErr;

            }

        }

        //配置的策略为如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。

        //嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,

        //那么其行为与PROPAGATION_REQUIRED一样

        if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {

            if (!isNestedTransactionAllowed()) {

                throw new NestedTransactionNotSupportedException(

                        "Transaction manager does not allow nested transactions by default - " +

                        "specify 'nestedTransactionAllowed' property with value 'true'");

            }

            if (debugEnabled) {

                logger.debug("Creating nested transaction with name [" + definition.getName() + "]");

            }

            if (useSavepointForNestedTransaction()) {

                // Create savepoint within existing Spring-managed transaction,

                // through the SavepointManager API implemented by TransactionStatus.

                // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.

                DefaultTransactionStatus status =

                        prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);

                status.createAndHoldSavepoint();

                return status;

            }

            else {

                // Nested transaction through nested begin and commit/rollback calls.

                // Usually only for JTA: Spring synchronization might get activated here

                // in case of a pre-existing JTA transaction.

                boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);

                DefaultTransactionStatus status = newTransactionStatus(

                        definition, transaction, true, newSynchronization, debugEnabled, null);

                doBegin(transaction, definition);

                prepareSynchronization(status, definition);

                return status;

            }

        }

        // Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.

        if (debugEnabled) {

            logger.debug("Participating in existing transaction");

        }

        if (isValidateExistingTransaction()) {

            if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {

                Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();

                if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {

                    Constants isoConstants = DefaultTransactionDefinition.constants;

                    throw new IllegalTransactionStateException("Participating transaction with definition [" +

                            definition + "] specifies isolation level which is incompatible with existing transaction: " +

                            (currentIsolationLevel != null ?

                                    isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :

                                    "(unknown)"));

                }

            }

            if (!definition.isReadOnly()) {

                if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {

                    throw new IllegalTransactionStateException("Participating transaction with definition [" +

                            definition + "] is not marked as read-only but existing transaction is");

                }

            }

        }

        boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);

        return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);

    }

获取更多学习资料,可以加群:473984645或扫描下方二维码

spring 声明式事务原理解读的更多相关文章

  1. spring声明式事务管理总结

    事务配置 首先在/WEB-INF/applicationContext.xml添加以下内容: <!-- 配置事务管理器 --> <bean id="transactionM ...

  2. Spring声明式事务管理基于@Transactional注解

    概述:我们已知道Spring声明式事务管理有两种常用的方式,一种是基于tx/aop命名空间的xml配置文件,另一种则是基于@Transactional 注解.         第一种方式我已在上文为大 ...

  3. Spring声明式事务配置管理方法

    环境配置 项目使用SSH架构,现在要添加Spring事务管理功能,针对当前环境,只需要添加Spring 2.0 AOP类库即可.添加方法: 点击项目右键->Build Path->Add ...

  4. Spring声明式事务配置管理方法(转)

    项目使用SSH架构,现在要添加Spring事务管理功能,针对当前环境,只需要添加Spring 2.0 AOP类库即可.添加方法: 点击项目右键->Build Path->Add libra ...

  5. Spring声明式事务的配置~~~

    /*2011年8月28日 10:03:30 by Rush  */ 环境配置 项目使用SSH架构,现在要添加Spring事务管理功能,针对当前环境,只需要添加Spring 2.0 AOP类库即可.添加 ...

  6. 深刻理解Spring声明式事务

    问题引入 Spring中事务传播有哪几种,分别是怎样的? 理解注解事务的自动配置? SpringBoot启动类为什么不需要加@EnableTransactionManagement注解? 声明式事务的 ...

  7. spring 声明式事务管理

    简单理解事务: 比如你去ATM机取5000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉5000元钱:然后ATM出5000元钱.这两个步骤必须是要么都执行要么都不执行.如果银行卡扣除了5000块但 ...

  8. Spring声明式事务管理基于tx/aop命名空间

    目的:通过Spring AOP 实现Spring声明式事务管理; Spring支持编程式事务管理和声明式事务管理两种方式. 而声明式事务管理也有两种常用的方式,一种是基于tx/aop命名空间的xml配 ...

  9. 161117、使用spring声明式事务抛出 identifier of an instance of

    今天项目组有成员使用spring声明式事务出现下面异常,这里跟大家分享学习下. 异常信息: org.springframework.orm.hibernate3.HibernateSystemExce ...

随机推荐

  1. Python Numpy 矩阵级基本操作(1)

    NumPy的操作介绍 import numpy as np #导入numpy包,简写为np print "Generate 1*10 matrix" a=np.arange(1,1 ...

  2. Django框架(二十)—— Django rest_framework-认证组件

    目录 Django rest_framework-认证组件 一.什么是认证 二.利用token记录认证过的用户 1.什么是token 2.token的原理 3.cookie.session.token ...

  3. linux中常用的命令大全

    系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS ...

  4. Spring Boot 2.1.6 发布了!

    Java技术栈 www.javastack.cn 优秀的Java技术公众号 最新消息: Spring Boot 2.1.6 昨天正式发布了,日常更新一些依赖和修复一些 BUG,没什么硬菜! 重点来了, ...

  5. Python面试题之“猴子补丁”(monkey patching)指的是什么?这种做法好吗?

    “猴子补丁”就是指,在函数或对象已经定义之后,再去改变它们的行为. 举个例子: import datetime datetime.datetime.now = lambda: datetime.dat ...

  6. CTU OPEN 2017 Shooting Gallery /// 区间DP

    题目大意: 给定n 给定n个数 选定一个区间留下其他消去 要求区间两端的两个数一样 若成功留下一个区间 则在选定区间的基础上 继续进行上述操作 直到无法再选出这样的区间 求最多操作数 按区间长度由短到 ...

  7. Spring学习笔记(1)——初识Spring

    一.Spring是什么       通常说的Spring其实指的是Spring Framework,它是Spring下的一个子项目,Spring围绕Spring Framework这个核心项目开发了大 ...

  8. Chrome不支持css字体小于12px的解决办法

    我们先来看个效果图(chrome下): 从上面的图可以很明显地看出Chrome下css设置字体大小为12px及以下时,显示的都是一样大小,都是默认12px: 那么网上有一个方法就是给当前样式添加Chr ...

  9. 出现异常: 非介入式客户端验证规则中的验证类型名称必须唯一。下列验证类型出现重复: required

    在将web.config文件中的<add key="ClientValidationEnabled" value="false" /> 设为fals ...

  10. 在MyEclipse中更换或修改svn的用户名和密码

    1.通过删除SVN客户端的账号配置文件     (1)找到我们使用的客户端配置文件,Windows XP中的位置是在系统盘的Documents and Settings\Administrator\A ...