在j2ee开发中实现事务的方式有编程式事务和基于aop的注解事务。编程事务通过手写jdbc,手动获取数据库连接,手动处理commit和rollback,这种方式有大量重复的代码和业务代码耦合,而且jdbc原生不支持事务的传播属性;
为了解决以上这些问题,Spring使用基于Aop注解式事务解决大量重复代码耦合问题,也基于注解的方式实现了一套事务传播处理机制。
Aop注解式事务的切入原理在前面已经分析了,这里看一下事务是怎么开启,commit,rollbak, 事务传播机制spring是怎么实现的。
1.从Aop事务的增强切入点开始
TransactionInterceptor,实现了MethodInterceptor和Advice接口代表Aop的一个增强,MethodInterceptor这个在创建代理的时候会被jdk动态代理或cglib代理类回调。业务方法被封装在MethodInvocation这个参数里。这个类继承了TransactionAspectSupport,this.invokeWithinTransaction(var10001, targetClass, invocation::proceed); 其实调用的是TransactionAspectSupport类的protected方法invokeWithinTransaction, 这个方法开启了spring进行事务增强的逻辑。
2.TransactionAspectSupport类的方法invokeWithinTransaction
@Nullable protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, TransactionAspectSupport.InvocationCallback invocation) throws Throwable { TransactionAttributeSource tas = this.getTransactionAttributeSource(); TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null; //获取数据库TransactionManager 默认配置的是DatasourceTransactionManager PlatformTransactionManager tm = this.determineTransactionManager(txAttr); String joinpointIdentification = this.methodIdentification(method, targetClass, txAttr); Object result; if (txAttr != null && tm instanceof CallbackPreferringPlatformTransactionManager) { //这里datasourceTransactionManager没有实现CallbackPreferringPlatformTransactionManager这个分支不用看 TransactionAspectSupport.ThrowableHolder throwableHolder = new TransactionAspectSupport.ThrowableHolder(); try { result = ((CallbackPreferringPlatformTransactionManager)tm).execute(txAttr, (status) -> { TransactionAspectSupport.TransactionInfo txInfo = this.prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); Object var9; try { Object var8 = invocation.proceedWithInvocation(); return var8; } catch (Throwable var13) { if (txAttr.rollbackOn(var13)) { if (var13 instanceof RuntimeException) { throw (RuntimeException)var13; } throw new TransactionAspectSupport.ThrowableHolderException(var13); } throwableHolder.throwable = var13; var9 = null; } finally { this.cleanupTransactionInfo(txInfo); } return var9; }); if (throwableHolder.throwable != null) { throw throwableHolder.throwable; } else { return result; } } catch (TransactionAspectSupport.ThrowableHolderException var19) { throw var19.getCause(); } catch (TransactionSystemException var20) { if (throwableHolder.throwable != null) { this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable); var20.initApplicationException(throwableHolder.throwable); } throw var20; } catch (Throwable var21) { if (throwableHolder.throwable != null) { this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable); } throw var21; } } else {//只要看这个分支就可以了 //这里创建事务,即开启了事务,把事务信息放进txInfo TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification); result = null; try { result = invocation.proceedWithInvocation();//执行业务方法 } catch (Throwable var17) { this.completeTransactionAfterThrowing(txInfo, var17);//如果抛异常则回滚 throw var17; } finally { this.cleanupTransactionInfo(txInfo);//调用业务方法结束后清除线程里的本次事务信息 } this.commitTransactionAfterReturning(txInfo);//正常结束提交事务 return result; } }
public interface PlatformTransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
void commit(TransactionStatus var1) throws TransactionException;
void rollback(TransactionStatus var1) throws TransactionException;
}
TransactionAttributeSource和TransactionAttribute封装了@Transaciton事务的配置信息包括传播属性,rollback的异常,隔离级别,超时时间等。PlatformTransactionManager是事务管理者接口,这个接口getTransaction,commit,rollback方法,getTransaction返回值TransactionStatus这个类封装事务的状态信息。PlatformTransactionManager具体实现有DatasourceTransactionManager,PlatformTransactionManager等,Spring默认大多数用的是DatasourceTransactionManager。DatasourceTransactionManager没有实现CallbackPreferringPlatformTransactionManager这个接口所有上面代码的第一个分支没走到,只要看else这个分支就可以了。 TransactionAspectSupport.TransactionInfo 这个类封装了事务的很多信息,包括定义,状态等信息。下面分析红色部分的调用方法
3. TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification); 这个方法是获取事务和数据库连接。
protected TransactionAspectSupport.TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm, @Nullable 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) { //这里创建事务,根据传播属性决定是否创建数据库连接,新事务会创建数据库连接。 status = tm.getTransaction((TransactionDefinition)txAttr); } else if (this.logger.isDebugEnabled()) { this.logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured"); } } //这个方法绑定当前事务信息到当前线程里,面用threadlocal实现。在spring的事务框架上thradlocal用的很多,包括数据库连接和事务属性都放在threadlocal里,theadlocal主要用来保存一个线程中的所有事务。一个线程的栈里方法有多个,可能配置了多个事务,这些事务有些开启了新的数据库连接,有些没开启只是引用了其他事务的数据库连接,这些都放在threadlocal里,整个事务传播属性也是基于threadlocal实现的。 return this.prepareTransactionInfo(tm, (TransactionAttribute)txAttr, joinpointIdentification, status); }
4.status = tm.getTransaction((TransactionDefinition)txAttr); 这句根据事务定义开启事务获取状态数据库连接。
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException { Object transaction = this.doGetTransaction();//创建事务 boolean debugEnabled = this.logger.isDebugEnabled(); if (definition == null) { definition = new DefaultTransactionDefinition(); } //这里判断是否已经存在旧的事务,这里面使用theadlaocl来判断的,如果线程里已经有数据库连接了说明已经存在旧的事务了。 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) { if (((TransactionDefinition)definition).getIsolationLevel() != -1 && this.logger.isWarnEnabled()) { this.logger.warn("Custom isolation level specified but no actual transaction initiated; isolation level will effectively be ignored: " + definition); } boolean newSynchronization = this.getTransactionSynchronization() == 0; return this.prepareTransactionStatus((TransactionDefinition)definition, (Object)null, true, newSynchronization, debugEnabled, (Object)null); } else { AbstractPlatformTransactionManager.SuspendedResourcesHolder suspendedResources = this.suspend((Object)null); if (debugEnabled) { this.logger.debug("Creating new transaction with name [" + ((TransactionDefinition)definition).getName() + "]: " + definition); } try { boolean newSynchronization = this.getTransactionSynchronization() != 2; DefaultTransactionStatus status = this.newTransactionStatus((TransactionDefinition)definition, transaction, true, newSynchronization, debugEnabled, suspendedResources); this.doBegin(transaction, (TransactionDefinition)definition); this.prepareSynchronization(status, (TransactionDefinition)definition); return status; } catch (Error | RuntimeException var7) { this.resume((Object)null, suspendedResources); throw var7; } } } @Override protected Object doGetTransaction() { DataSourceTransactionObject txObject = new DataSourceTransactionObject(); txObject.setSavepointAllowed(isNestedTransactionAllowed()); ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource()); txObject.setConnectionHolder(conHolder, false);//这里封装了threadloacl从当前线程获取数据库连接 return txObject; }
//如果已经存在旧的事务就走下面这个方法,这个方法根据getPropagationBehavior即传播属性来处理不同的逻辑,现在分析默认情况PROPAGATION_REQUIRED时。 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 suspendedResources; boolean newSynchronization; if (definition.getPropagationBehavior() == 4) { if (debugEnabled) { this.logger.debug("Suspending current transaction"); } suspendedResources = this.suspend(transaction); newSynchronization = this.getTransactionSynchronization() == 0; return this.prepareTransactionStatus(definition, (Object)null, false, newSynchronization, debugEnabled, suspendedResources); } else if (definition.getPropagationBehavior() == 3) { if (debugEnabled) { this.logger.debug("Suspending current transaction, creating new transaction with name [" + definition.getName() + "]"); } suspendedResources = this.suspend(transaction); try { newSynchronization = this.getTransactionSynchronization() != 2; DefaultTransactionStatus status = this.newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources); this.doBegin(transaction, definition); this.prepareSynchronization(status, definition); return status; } catch (Error | RuntimeException var7) { this.resumeAfterBeginException(transaction, suspendedResources, var7); throw var7; } } else { boolean newSynchronization; 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 status = this.prepareTransactionStatus(definition, transaction, false, false, debugEnabled, (Object)null); status.createAndHoldSavepoint(); return status; } else { newSynchronization = this.getTransactionSynchronization() != 2; DefaultTransactionStatus status = this.newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, (Object)null); this.doBegin(transaction, definition); this.prepareSynchronization(status, definition); return status; } } } else { if (debugEnabled) { this.logger.debug("Participating in existing transaction"); } if (this.isValidateExistingTransaction()) { if (definition.getIsolationLevel() != -1) { 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, "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"); } } //默认情况会走到最后这个分支,这里没有调用dobeging开启数据库连接而是复用了外围事务的数据库连接,即如果当前存在事务,加入当期事务。 newSynchronization = this.getTransactionSynchronization() != 2; return this.prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, (Object)null); } } } }
下面来开一下默认隔离级别PROPAGATION_REQUIRED是如何回滚和提交的。
private void processRollback(DefaultTransactionStatus status, boolean unexpected) { try { boolean unexpectedRollback = unexpected; try { this.triggerBeforeCompletion(status); if (status.hasSavepoint()) { if (status.isDebug()) { this.logger.debug("Rolling back transaction to savepoint"); } status.rollbackToHeldSavepoint(); } else if (status.isNewTransaction()) { if (status.isDebug()) { this.logger.debug("Initiating transaction rollback"); } this.doRollback(status); } else { if (status.hasTransaction()) { if (!status.isLocalRollbackOnly() && !this.isGlobalRollbackOnParticipationFailure()) { if (status.isDebug()) { this.logger.debug("Participating transaction failed - letting transaction originator decide on rollback"); } } else { if (status.isDebug()) { this.logger.debug("Participating transaction failed - marking existing transaction as rollback-only"); } this.doSetRollbackOnly(status);//由于是默认隔离级别当前如果存在事务,如果出现异常不会回滚只是在事务链上设置回滚标记。 } } else { this.logger.debug("Should roll back transaction but cannot - no transaction available"); } if (!this.isFailEarlyOnGlobalRollbackOnly()) { unexpectedRollback = false; } } } catch (Error | RuntimeException var8) { this.triggerAfterCompletion(status, 2); throw var8; } this.triggerAfterCompletion(status, 1); if (unexpectedRollback) { throw new UnexpectedRollbackException("Transaction rolled back because it has been marked as rollback-only"); } } finally { this.cleanupAfterCompletion(status); } }
ublic final void commit(TransactionStatus status) throws TransactionException { if (status.isCompleted()) { throw new IllegalTransactionStateException("Transaction is already completed - do not call commit or rollback more than once per transaction"); } else { DefaultTransactionStatus defStatus = (DefaultTransactionStatus)status; if (defStatus.isLocalRollbackOnly()) { if (defStatus.isDebug()) { this.logger.debug("Transactional code has requested rollback"); } this.processRollback(defStatus, false); } else if (!this.shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {// defStatus.isGlobaleTollbakcOnly这个方法会判断事务链上是否存在回滚标记,如果存在则当前事务不commit,直接回滚 if (defStatus.isDebug()) { this.logger.debug("Global transaction is marked as rollback-only but transactional code requested commit"); } this.processRollback(defStatus, true); } else { this.processCommit(defStatus); } } }
下面这个方法是从transaction里查询出回滚标记,transation里封装了threadloal,这里取出的是同一个线程开启的另外一个事务出现异常异常是在processRollback方法this.doSetRollbackOnly(status)里设置的回滚标记。
public boolean isGlobalRollbackOnly() { return this.transaction instanceof SmartTransactionObject && ((SmartTransactionObject)this.transaction).isRollbackOnly(); }
至此默认隔离级别下PROPAGATION_REQUIRED,事务提交回滚分析结束。