// public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor// org.springframework.transaction.interceptor.TransactionInterceptor#invoke@Override@NullablepublicObjectinvoke(MethodInvocation invocation)throwsThrowable{// 获取被代理的类// 因为TransactionAttribute是间接的跟targetClass绑定的// 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);// step into ...// Adapt to TransactionAspectSupport's invokeWithinTransaction...returninvokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);}// org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction@NullableprotectedObjectinvokeWithinTransaction(Method method,@NullableClass<?> targetClass,finalInvocationCallback invocation)throwsThrowable{// 直接返回,即return this.transactionAttributeSource;// 基于注解(声明式事务)的属性源是AnnotationTransactionAttributeSource// If the transaction attribute is null, the method is non-transactional.TransactionAttributeSource tas =getTransactionAttributeSource();// 根据TransactionAttributeSource获取对应方法(需要有事务的话)的事务参数TransactionAttribute// 其实就是AOP之前解析@Transactional注解获取事务参数的那个过程// 因此,这里我们就不再 step into 了finalTransactionAttribute txAttr =(tas !=null? tas.getTransactionAttribute(method, targetClass):null);// step into ...// 确定使用的事务管理器TransactionManagerfinalTransactionManager tm =determineTransactionManager(txAttr);// 这里用于spring5的响应式编程,略过吧if(this.reactiveAdapterRegistry !=null&& tm instanceofReactiveTransactionManager){// ...return txSupport.invokeWithinTransaction(
method, targetClass, invocation, txAttr,(ReactiveTransactionManager) tm);}// 强转事务管理器的类型PlatformTransactionManager ptm =asPlatformTransactionManager(tm);// step into ...// 获取需要纳入事务的方法的joinpoint连接点相关的信息,主要用作记录日志finalString joinpointIdentification =methodIdentification(method, targetClass, txAttr);if(txAttr ==null||!(ptm instanceofCallbackPreferringPlatformTransactionManager)){// step into ...// 创建事务// Standard transaction demarcation with getTransaction and commit/rollback calls.TransactionInfo txInfo =createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);Object retVal;try{// 其实就是调用方法入参中的回调函数,说白了就是aop过程中的MethodInvocation.proceed()// 就像是一个环绕通知,在这里做了对下一个拦截器的调用罢了// 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 exceptioncompleteTransactionAfterThrowing(txInfo, ex);// 重新抛出这个异常throw ex;}finally{// 清理当前绑定的事务信息、恢复之前的事务绑定cleanupTransactionInfo(txInfo);}// 略过吧...//类路径上存在Vavr库时的处理,这个需要引入外部依赖,因此一般都是不存在的if(retVal !=null&& vavrPresent &&VavrDelegate.isVavrTry(retVal)){// Set rollback-only in case of Vavr failure matching our rollback rules...TransactionStatus status = txInfo.getTransactionStatus();if(status !=null&& txAttr !=null){
retVal =VavrDelegate.evaluateTryFailure(retVal, txAttr, status);}}// 目标方法成功执行之后,返回结果之前提交事务commitTransactionAfterReturning(txInfo);// 事务正常处理完毕,返回事务方法的执行结果return retVal;}else{// 先略过吧,这一块目前不太接触得到// 如果txAttr不为null并且事务管理器属于CallbackPreferringPlatformTransactionManager,走下面的逻辑}}
2. determineTransactionManager:确立并返回对应的事务管理器
// org.springframework.transaction.interceptor.TransactionAspectSupport#determineTransactionManager@NullableprotectedTransactionManagerdetermineTransactionManager(@NullableTransactionAttribute txAttr){// Do not attempt to lookup tx manager if no tx attributes are setif(txAttr ==null||this.beanFactory ==null){returngetTransactionManager();}// 根据@Transactional中的value属性指定了事务管理器String qualifier = txAttr.getQualifier();if(StringUtils.hasText(qualifier)){returndetermineQualifiedTransactionManager(this.beanFactory, qualifier);}elseif(StringUtils.hasText(this.transactionManagerBeanName)){returndetermineQualifiedTransactionManager(this.beanFactory,this.transactionManagerBeanName);}else{// 这里就是return this.txmanager,此时还是null// 默认set的事务管理器是个NullTransactionManager defaultTransactionManager =getTransactionManager();if(defaultTransactionManager ==null){// 尝试命中事务管理器的缓存// 缓存第一次访问也是null
defaultTransactionManager =this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);if(defaultTransactionManager ==null){// 在ioc容器中找到TransactionManager类型的bean注入// 这里我们获取到的是DateSourceTransactionManager
defaultTransactionManager =this.beanFactory.getBean(TransactionManager.class);// 缓存起来this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);}}// end ...return defaultTransactionManager;}}
// org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessaryprotectedTransactionInfocreateTransactionIfNecessary(@NullablePlatformTransactionManager tm,@NullableTransactionAttribute txAttr,finalString joinpointIdentification){// 如果TransactionAttribute为null,则创建一个并且以方法的被代理的全限定名作为连接点标识// If no name specified, apply method identification as transaction name.if(txAttr !=null&& txAttr.getName()==null){
txAttr =newDelegatingTransactionAttribute(txAttr){@OverridepublicStringgetName(){return joinpointIdentification;}};}TransactionStatus status =null;if(txAttr !=null){if(tm !=null){// step into ...// 获取到一个TransactionStatus
status = tm.getTransaction(txAttr);}else{if(logger.isDebugEnabled()){
logger.debug("Skipping transactional joinpoint ["+ joinpointIdentification +"] because no transaction manager has been configured");}}}// step into ...returnprepareTransactionInfo(tm, txAttr, joinpointIdentification, status);}
4.1 getTransaction:从事务管理器中获取一个TransactionStatus
// org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction@OverridepublicfinalTransactionStatusgetTransaction(@NullableTransactionDefinition definition)throwsTransactionException{// 如果TransactionAttribute为null,则创建一个默认的// Use defaults if no transaction definition given.TransactionDefinition def =(definition !=null? definition :TransactionDefinition.withDefaults());// step into ...// 获取当前事务,该方法由具体的事务管理器子类自己实现,比如DataSourceTransactionManager、JtaTransactionManager// 对于DataSourceTransactionManager这里获取的实际上是一个数据库的事务连接对象,即DataSourceTransactionObjectObject transaction =doGetTransaction();boolean debugEnabled = logger.isDebugEnabled();// step into ...// 是否开启事务 if(isExistingTransaction(transaction)){// Existing transaction found -> check propagation behavior to find out how to behave.returnhandleExistingTransaction(def, transaction, debugEnabled);}// 事务超时// 默认不设限// Check definition settings for new transaction.if(def.getTimeout()<TransactionDefinition.TIMEOUT_DEFAULT){thrownewInvalidTimeoutException("Invalid transaction timeout", def.getTimeout());}// 当事务传播行为是PROPAGATION_MANDATORY(如果存在事务,抛出异常)// No existing transaction found -> check propagation behavior to find out how to proceed.if(def.getPropagationBehavior()==TransactionDefinition.PROPAGATION_MANDATORY){thrownewIllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");}// 当事务传播类型为...是,允许存在事务elseif(def.getPropagationBehavior()==TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior()==TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior()==TransactionDefinition.PROPAGATION_NESTED){// step into ...//暂停给定的事务。首先挂起事务同步,然后再委派给doSuspend模板方法。//由于此前没有事务,所以参数事务为nullSuspendedResourcesHolder suspendedResources =suspend(null);if(debugEnabled){
logger.debug("Creating new transaction with name ["+ def.getName()+"]: "+ def);}try{// step into ...//开启一个新事务并返回returnstartTransaction(def, transaction, debugEnabled, suspendedResources);}catch(RuntimeException|Error ex){resume(null, suspendedResources);throw ex;}}else{// Create "empty" transaction: no actual transaction, but potentially synchronization.if(def.getIsolationLevel()!=TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()){
logger.warn("Custom isolation level specified but no actual transaction initiated; "+"isolation level will effectively be ignored: "+ def);}// step into ...boolean newSynchronization =(getTransactionSynchronization()== SYNCHRONIZATION_ALWAYS);// step into ...returnprepareTransactionStatus(def,null,true, newSynchronization, debugEnabled,null);}}
// org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin@OverrideprotectedvoiddoBegin(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(newConnectionHolder(newCon),true);}// 获取事务对象的连接持有者,将synchronizedWithTransaction设置为true,即资源标记为与事务同步。
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();// 赋值配置的事务隔离级别Integer previousIsolationLevel =DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
txObject.setReadOnly(definition.isReadOnly());// 是否设置自动提交事务// 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");}/*
* 如果上面判断是自动提交,那么切换为手动提交,为什么呢?如果不手动提交,
* 那么一个方法中执行多个sql语句时将会每执行一个提交一次,无法实现事务的控制
* 开启手动提交就能实现方法级别的整体事务控制
*
* 并且,开启手动提交时,将会自动开启事物
*/
con.setAutoCommit(false);}/*
*
* 事务开始后立即准备事务连接,主要是对于只读事务的优化操作(需要手动开启)
* 如果将"enforceReadOnly"标志设置为true(默认为false),并且事务定义指示只读事务,
* 则默认实现将执行"SET TRANSACTION READ ONLY"这一个sql语句。
* 请注意mysql只读事务不要开启,oracle的只读事务可以开启
*/prepareTransactionalConnection(con, definition);// 设置事务ConnectionHolder的transactionActive属性为true,表示激活当前连接的事务// 此前判断是否有开启事务的isExistingTransaction方法就会判断这个属性
txObject.getConnectionHolder().setTransactionActive(true);// 设置事务超时时间int timeout =determineTimeout(definition);if(timeout !=TransactionDefinition.TIMEOUT_DEFAULT){// step into ...
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);}// 如果是新的连接持有者,即newConnectionHolder属性为true// 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);}thrownewCannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);}}
4.1.4.1.1 setTimeoutInSeconds:事务超时配置传递到事务资源上
// org.springframework.transaction.support.ResourceHolderSupport#setTimeoutInSecondspublicvoidsetTimeoutInSeconds(int seconds){// step into ...// s -> mssetTimeoutInMillis(seconds *1000L);}// org.springframework.transaction.support.ResourceHolderSupport#setTimeoutInMillispublicvoidsetTimeoutInMillis(long millis){// 因为事务创建、开启是在第一个SQL代码的调用时候// 因此可以知道SQL执行前延时将影响到超时,放SQL调用后不会有任何影响// step out ...this.deadline =newDate(System.currentTimeMillis()+ millis);}
// org.springframework.transaction.interceptor.TransactionAspectSupport#prepareTransactionInfoprotectedTransactionInfoprepareTransactionInfo(@NullablePlatformTransactionManager tm,@NullableTransactionAttribute txAttr,String joinpointIdentification,@NullableTransactionStatus status){TransactionInfo txInfo =newTransactionInfo(tm, txAttr, joinpointIdentification);if(txAttr !=null){// We need a transaction for this method...if(logger.isTraceEnabled()){
logger.trace("Getting transaction for ["+ txInfo.getJoinpointIdentification()+"]");}// 创建新事务的TransactionStatus// The transaction manager will flag an error if an incompatible tx already exists.
txInfo.newTransactionStatus(status);}else{// The TransactionInfo.hasTransaction() method will return false. We created it only// to preserve the integrity of the ThreadLocal stack maintained in this class.if(logger.isTraceEnabled()){
logger.trace("No need to create transaction for ["+ joinpointIdentification +"]: This method is not transactional.");}}// 将resourceHolder(ConnectHolder)绑定到当前线程// We always bind the TransactionInfo to the thread, even if we didn't create// a new transaction here. This guarantees that the TransactionInfo stack// will be managed correctly even if no transaction was created by this aspect.
txInfo.bindToThread();return txInfo;}// org.springframework.transaction.interceptor.TransactionAspectSupport.TransactionInfo#bindToThreadprivatevoidbindToThread(){// Expose current TransactionStatus, preserving any existing TransactionStatus// for restoration after this transaction is complete.this.oldTransactionInfo = transactionInfoHolder.get();
transactionInfoHolder.set(this);}