spring 聲明式事務原理解讀

在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環繞通知)類型的切面。

---------------------------------TODO------------------------------------------------
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);
		}
hasHibernateManagedTransaction函數實現如下:
public boolean hasHibernateManagedTransaction() {
            return this.sessionHolder != null && this.sessionHolder.getSession().getTransaction().isActive();
        }
這兩個函數都很簡單,結合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);
	}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章