博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring 源码学习笔记(二)事务管理
阅读量:2353 次
发布时间:2019-05-10

本文共 12384 字,大约阅读时间需要 41 分钟。

spring 事务管理会帮我们自动管理数据库的事务,没读源码前觉得很神秘,读了源码发现原理还是很简单的。

本质上还是用的 jdbc 的事务管理。spring 在调用某个方法前,判断是否需要事务,如果需要,则调用

con.setAutoCommit(false);//开启事务

来开启事务,然后通过反射调用操作数据库的方法,如果抛出异常则执行

con.rollback();//回滚事务

来回滚事务,否则执行

con.commit();//try的最后提交事务

来提交事务。

 

下面让我们仔细看看源码吧

首先是怎么找到 spirng 事务的源码,我采用的方法是在要调用的 servie 里加断点,然后查看方法的堆栈

发现 invoke ,点进去

@Override	@Nullable	public Object invoke(final MethodInvocation invocation) throws Throwable {		// Work out the target class: may be {@code null}.		// The TransactionAttributeSource should be passed the target class		// as well as the method, which may be from an interface.		Class
targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); // Adapt to TransactionAspectSupport's invokeWithinTransaction... return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed); }

再进入 invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);

/**	 * 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	 */	@Nullable	protected Object invokeWithinTransaction(Method method, @Nullable Class
targetClass, final InvocationCallback invocation) throws Throwable { // If the transaction attribute is null, the method is non-transactional. TransactionAttributeSource tas = getTransactionAttributeSource(); final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null); final PlatformTransactionManager tm = determineTransactionManager(txAttr); final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. 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 { final ThrowableHolder throwableHolder = new ThrowableHolder(); // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in. try { Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, 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. throwableHolder.throwable = ex; return null; } } finally { cleanupTransactionInfo(txInfo); } }); // Check result state: It might indicate a Throwable to rethrow. if (throwableHolder.throwable != null) { throw throwableHolder.throwable; } return result; } catch (ThrowableHolderException ex) { throw ex.getCause(); } catch (TransactionSystemException ex2) { if (throwableHolder.throwable != null) { logger.error("Application exception overridden by commit exception", throwableHolder.throwable); ex2.initApplicationException(throwableHolder.throwable); } throw ex2; } catch (Throwable ex2) { if (throwableHolder.throwable != null) { logger.error("Application exception overridden by commit exception", throwableHolder.throwable); } throw ex2; } } }

再这个方法里,我们就和上面 jdbc 的操作对应起来了,

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

这一句,如果必须则开启一个新的事务。

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;

调用 service 方法,抛出异常执行 completeTransactionAfterThrowing(txInfo, ex);回滚

否则 commitTransactionAfterReturning(txInfo);提交事务。

下面进入 

createTransactionIfNecessary(tm, txAttr, joinpointIdentification)

这个方法看看

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

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(@Nullable PlatformTransactionManager tm, @Nullable 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"); } } } return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); }

发现获取事务方法 

status = tm.getTransaction(txAttr);

继续跟进

/**	 * This implementation handles propagation behavior. Delegates to	 * {@code doGetTransaction}, {@code isExistingTransaction}	 * and {@code doBegin}.	 * @see #doGetTransaction	 * @see #isExistingTransaction	 * @see #doBegin	 */	@Override	public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {		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();		}		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 | Error ex) {				resume(null, suspendedResources);				throw ex;			}		}		else {			// Create "empty" transaction: no actual transaction, but potentially synchronization.			if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {				logger.warn("Custom isolation level specified but no actual transaction initiated; " +						"isolation level will effectively be ignored: " + definition);			}			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);			return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);		}	}

继续跟进 

doBegin(transaction, definition);

这个方法,发现这个方法有三个实现,我们这里选择第二个,jdbc的实现。

点进去

/**	 * This implementation sets the isolation level but ignores the timeout.	 */	@Override	protected void doBegin(Object transaction, TransactionDefinition definition) {		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;		Connection con = null;		try {			if (!txObject.hasConnectionHolder() ||					txObject.getConnectionHolder().isSynchronizedWithTransaction()) {				Connection newCon = obtainDataSource().getConnection();				if (logger.isDebugEnabled()) {					logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");				}				txObject.setConnectionHolder(new ConnectionHolder(newCon), true);			}			txObject.getConnectionHolder().setSynchronizedWithTransaction(true);			con = txObject.getConnectionHolder().getConnection();			Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);			txObject.setPreviousIsolationLevel(previousIsolationLevel);			// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,			// so we don't want to do it unnecessarily (for example if we've explicitly			// configured the connection pool to set it already).			if (con.getAutoCommit()) {				txObject.setMustRestoreAutoCommit(true);				if (logger.isDebugEnabled()) {					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");				}				con.setAutoCommit(false);			}			prepareTransactionalConnection(con, definition);			txObject.getConnectionHolder().setTransactionActive(true);			int timeout = determineTimeout(definition);			if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {				txObject.getConnectionHolder().setTimeoutInSeconds(timeout);			}			// Bind the connection holder to the thread.			if (txObject.isNewConnectionHolder()) {				TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());			}		}		catch (Throwable ex) {			if (txObject.isNewConnectionHolder()) {				DataSourceUtils.releaseConnection(con, obtainDataSource());				txObject.setConnectionHolder(null, false);			}			throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);		}	}

在这里我们终于看到 熟悉的 jdbc 开启事务的代码

/ Switch to manual commit if necessary. This is very expensive in some JDBC drivers,			// so we don't want to do it unnecessarily (for example if we've explicitly			// configured the connection pool to set it already).			if (con.getAutoCommit()) {				txObject.setMustRestoreAutoCommit(true);				if (logger.isDebugEnabled()) {					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");				}				con.setAutoCommit(false);			}

对于回滚和提交操作,和开始事务的代码一样,这里就不在赘述了。

好了,spring 的事务管理基本原理已经了解的差不多了,有时间再搞一下 spring 的事务传播机制的源码。

你可能感兴趣的文章
Tab Layout 之多个Activity实现
查看>>
FrameLayout之我见
查看>>
个人解读Activity之一
查看>>
实现自定义布局的Notification
查看>>
AlarmManager的学习与实现
查看>>
解读Content Provider之一
查看>>
解读Content Provider之二
查看>>
自定义UI实例
查看>>
推荐一个不错的自定义UI
查看>>
fedora16 设置 gedit软件的默认编码
查看>>
S3C6410 存储器映射
查看>>
Linux 3.3.0移植到S3C6410开发板上之一
查看>>
Busybox支持中文的解决办法
查看>>
Spring中BeanFactory和FactoryBean有什么区别?
查看>>
牛年(2021)的KPI
查看>>
快速识别图片类型
查看>>
理解云原生
查看>>
docker常见问题答疑
查看>>
mac最简配置maven
查看>>
虚拟机性能监控与故障处理工具
查看>>