菜是原罪之回温Spring事务

不是不会,菜是原罪
今天,today,localdatetime,⭐哥在🍋🏔上问了一个问题之本地事务的正确姿势,我很果断的说加try catch当时不知道哪里来的自信,⭐哥的一句我想杀死你聪聪,让我害怕了,秉着认真负责的态度,我还是去Baidu一下。
直接上来就说问题原因和解决办法有点突兀,所以还是一点点来说吧,先来聊一聊什么是事务
事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。–官方回答
事情开始到结束的整个过程称为一个事务 。–自己瞎扯的
事务的特性主要有四个方面(ACID),如果你不知道那就往下认真看,如果你知道那就在回顾一遍。
·原子性(atomicity):事务是数据库的逻辑工作单位,并且必须是原子工作单位(原子不可再分),对于其数据的修改,要么全部执行,要么全部不执行。
·一致性(consistency):事务在完成时,必须是所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保证所有数据的完整性。–简单举例就是在转账时转账双方的余额相加前后值不变
·隔离性(isolation):一个事务的执行不能被其他事务所影响。
·持久性(durability):一个事务一旦提交,事务的操作就永久保存在数据库中。即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。


事务分类:JDBC事务、JTA事务…,最常见的可能就是JDBC事务了,延续JDBC事务进行讲述。
在开发过程中可能对JDBC事务感知不是很深,但是有一个注解相信你肯定有用过吧:@Transcation,Spring声明式事务注解方式。为什么说这个呢?因为Spring的事务底层依赖MySQL的事务,代码层面上利用AOP实现。MySQL的事务有隔离级别的概念,只有InnoDB有事务,并且实现方式是利用undo log和redo log

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    @AliasFor("transactionManager")
    String value() default "";

    @AliasFor("value")
    String transactionManager() default "";

    Propagation propagation() default Propagation.REQUIRED;

    Isolation isolation() default Isolation.DEFAULT;

    int timeout() default -1;

    boolean readOnly() default false;

    Class<? extends Throwable>[] rollbackFor() default {};

    String[] rollbackForClassName() default {};

    Class<? extends Throwable>[] noRollbackFor() default {};

    String[] noRollbackForClassName() default {};
}

上边就是Transcation注解的属性,可以看到包括有事务控制器,传播行为等等…,可以看到默认的传播行为是REQUIRED即:如果当前存在事务,则假如当前事务,如果当前没有事务,则创建一个新的事务
除此之外,还有REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则将当前事务挂起
SUPPORTS:如果当前存在事务,则加入当前事务,如果当前没有事务,则以非事务方式继续运行
NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则将当前事务挂起
NEVER:以非事务方式运行,如果当前存在事务,则抛出异常
MANDATORY:如果当前存在事务,则加入当前事务,如果当前没有事务,则抛出异常
NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务,如果当前没有事务,则等同于REQUIRED
https://segmentfault.com/a/1190000013341344←这篇博客我觉得讲的还是挺清楚的
除此之外,我们还可以看到存在rollbackFor函数->代表着事务的回滚机制。
那么就来好好的说一下Spring事务的回滚机制,Spring的AOP(声明式事务管理)默认是针对unchecked exception回滚。Spring的事务边界是在调用业务方法之前开始的,业务方法执行完毕后来执行commit or rollback(取决于是否抛出异常)
在上边的时候也有提到Spring事务是基于Spring AOP思想实现的,但是仅仅@Transcation提供事务属性并不能真正的产生作用,所以我们可以预知到在这之前还有一步操作,那才是关键。这一步就是在启动类上加@EnableTranscationManagement注解,为什么这一步是关键呢?我们可以点进去看一下。

@Target(ElementType.TYPE)  
@Retention(RetentionPolicy.RUNTIME) 
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

	boolean proxyTargetClass() default false;

	AdviceMode mode() default AdviceMode.PROXY;
	
	int order() default Ordered.LOWEST_PRECEDENCE;

}

看上边可以看到注解首先导入了一个类,这个类的意义就是帮我们引入事务相关的组件到容器中。如下:

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

	/**
	 * 返回动态代理事务控制器配置或者aspectj事务控制器配置  -->默认是Proxy(动态代理)
	 * Returns {@link ProxyTransactionManagementConfiguration} or
	 * {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
	 * and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
	 * respectively.
	 */
	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				// 默认返回
				return new String[] {AutoProxyRegistrar.class.getName(),
						ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {determineTransactionAspectClass()};
			default:
				return null;
		}
	}

	private String determineTransactionAspectClass() {
		return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
				TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
				TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
	}

}

当进行断点调试的时候你会发现,默认switch case会走PROXY,返回自动代理注册类以及动态代理事务管理配置类。

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    private final Log logger = LogFactory.getLog(this.getClass());

    public AutoProxyRegistrar() {
    }

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean candidateFound = false;
        Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
        Iterator var5 = annTypes.iterator();

        while(var5.hasNext()) {
            String annType = (String)var5.next();
            AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
            if (candidate != null) {
                Object mode = candidate.get("mode");
                Object proxyTargetClass = candidate.get("proxyTargetClass");
                if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() && Boolean.class == proxyTargetClass.getClass()) {
                    candidateFound = true;
                    if (mode == AdviceMode.PROXY) {
                        AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                        if ((Boolean)proxyTargetClass) {
                            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                            return;
                        }
                    }
                }
            }
        }

        if (!candidateFound && this.logger.isInfoEnabled()) {
            String name = this.getClass().getSimpleName();
            this.logger.info(String.format("%s was imported but no annotations were found having both 'mode' and 'proxyTargetClass' attributes of type AdviceMode and boolean respectively. This means that auto proxy creator registration and configuration may not have occurred as intended, and components may not be proxied as expected. Check to ensure that %s has been @Import'ed on the same class where these annotations are declared; otherwise remove the import of %s altogether.", name, name, name));
        }

    }
}

进入自动代理注册类,我们可以看到,这个类实现了AOP向容器内注册服务的接口ImportBeanDefinitionRegistrar,那么究竟这个自动代理注册类向容器中注册了什么服务呢?通过我们断点mode == AdviceMode.PROXY(经验可以直接断在这里),进入下边AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);

public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
    return registerAutoProxyCreatorIfNecessary(registry, (Object)null);
}

@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
    return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}

可以看到会向容器中添加InfrastructureAdvisorAutoProxyCreator.class这个组件。
进入要添加的这个类,我们看一下到底是个啥。

public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
    @Nullable
    private ConfigurableListableBeanFactory beanFactory;

    public InfrastructureAdvisorAutoProxyCreator() {
    }

    protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        super.initBeanFactory(beanFactory);
        this.beanFactory = beanFactory;
    }

    protected boolean isEligibleAdvisorBean(String beanName) {
        return this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) && this.beanFactory.getBeanDefinition(beanName).getRole() == 2;
    }
}
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware 

看继承链的最顶端可以看到SmartInstantiationAwareBeanPostProcessor,是一个Bean的后置处理器。
Alt + 7 来看一下当前类的方法(尤其注意后置处理器的处理方法):
在这里插入图片描述
一个一个分析一下:

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
   Object cacheKey = this.getCacheKey(beanClass, beanName);
   if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
       if (this.advisedBeans.containsKey(cacheKey)) {
           return null;
       }

       if (this.isInfrastructureClass(beanClass) || this.shouldSkip(beanClass, beanName)) {
           this.advisedBeans.put(cacheKey, Boolean.FALSE);
           return null;
       }
   }

   TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);
   if (targetSource != null) {
       if (StringUtils.hasLength(beanName)) {
           this.targetSourcedBeans.add(beanName);
       }

       Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
       Object proxy = this.createProxy(beanClass, beanName, specificInterceptors, targetSource);
       this.proxyTypes.put(cacheKey, proxy.getClass());
       return proxy;
   } else {
       return null;
   }
}

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return this.wrapIfNecessary(bean, beanName, cacheKey);
        }
    }

    return bean;
}

后置回调器都是在容器的初始化生命周期中产生的作用,before是之前,after是之后,当你走断点就会发现每一个bean对象都会到这个回调器上来,尤其关注service层/controller层(你加@Transcation注解的那一层bean对象),看这两个处理方法的过程,你就会发现after回调方法会对service/controller的bean对象进行包装。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    } else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    } else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
        Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        } else {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
    } else {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }
}

达到的效果就是将下面的事务管理配置类中的配置bean对象包装到一起,创建出代理对象。

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 TransactionManager tm = determineTransactionManager(txAttr);

   if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
   	ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
   		if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
   			throw new TransactionUsageException(
   					"Unsupported annotated transaction on suspending function detected: " + method +
   					". Use TransactionalOperator.transactional extensions instead.");
   		}
   		ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
   		if (adapter == null) {
   			throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
   					method.getReturnType());
   		}
   		return new ReactiveTransactionSupport(adapter);
   	});
   	return txSupport.invokeWithinTransaction(
   			method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
   }

   PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
   final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

   if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
   	// Standard transaction demarcation with getTransaction and commit/rollback calls.
   	TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

   	Object retVal;
   	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);
   	}

   	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 {
   	Object result;
   	final ThrowableHolder throwableHolder = new ThrowableHolder();

   	// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
   	try {
   		result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
   			TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
   			try {
   				Object retVal = invocation.proceedWithInvocation();
   				if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
   					// Set rollback-only in case of Vavr failure matching our rollback rules...
   					retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
   				}
   				return retVal;
   			}
   			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);
   			}
   		});
   	}
   	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;
   	}

   	// Check result state: It might indicate a Throwable to rethrow.
   	if (throwableHolder.throwable != null) {
   		throw throwableHolder.throwable;
   	}
   	return result;
   }
}

上边就是真正AOP事务执行方法(代理类调用–>Cglib代理),其中事务执行成功以及回滚的方法如下:

try {
	retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
	completeTransactionAfterThrowing(txInfo, ex);
	throw ex;
}
finally {
	cleanupTransactionInfo(txInfo);
}

另外的ProxyTransactionManagementConfiguration事务管理配置类会向容器中添加Bean对象

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
			TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {

		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource);
		advisor.setAdvice(transactionInterceptor);
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource);
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}

通过上边的代码我们可以看到,注入的对象分别是:BeanFactoryTransactionAttributeSourceAdvisorTransactionAttributeSource 以及 TransactionInterceptor。那么接下来就要思考注入的这三个Bean对象是做什么的的。
秉着由易到难的态度,我们先从代码少的入手,先进入TransactionAttributeSource看看给我们new出来了个啥。


/**
 * Create a default AnnotationTransactionAttributeSource, supporting
 * public methods that carry the {@code Transactional} annotation
 * or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
 */
public AnnotationTransactionAttributeSource() {
	this(true);
}

/**
 * Create a custom AnnotationTransactionAttributeSource, supporting
 * public methods that carry the {@code Transactional} annotation
 * or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
 * @param publicMethodsOnly whether to support public methods that carry
 * the {@code Transactional} annotation only (typically for use
 * with proxy-based AOP), or protected/private methods as well
 * (typically used with AspectJ class weaving)
 */
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
	this.publicMethodsOnly = publicMethodsOnly;
	if (jta12Present || ejb3Present) {
		this.annotationParsers = new LinkedHashSet<>(4);
		this.annotationParsers.add(new SpringTransactionAnnotationParser());
		if (jta12Present) {
			this.annotationParsers.add(new JtaTransactionAnnotationParser());
		}
		if (ejb3Present) {
			this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
		}
	}
	else {
		this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
	}
}

/**
 * Create a custom AnnotationTransactionAttributeSource.
 * @param annotationParser the TransactionAnnotationParser to use
 */
public AnnotationTransactionAttributeSource(TransactionAnnotationParser annotationParser) {
	this.publicMethodsOnly = true;
	Assert.notNull(annotationParser, "TransactionAnnotationParser must not be null");
	this.annotationParsers = Collections.singleton(annotationParser);
}

/**
 * Create a custom AnnotationTransactionAttributeSource.
 * @param annotationParsers the TransactionAnnotationParsers to use
 */
public AnnotationTransactionAttributeSource(TransactionAnnotationParser... annotationParsers) {
	this.publicMethodsOnly = true;
	Assert.notEmpty(annotationParsers, "At least one TransactionAnnotationParser needs to be specified");
	this.annotationParsers = new LinkedHashSet<>(Arrays.asList(annotationParsers));
}

/**
 * Create a custom AnnotationTransactionAttributeSource.
 * @param annotationParsers the TransactionAnnotationParsers to use
 */
public AnnotationTransactionAttributeSource(Set<TransactionAnnotationParser> annotationParsers) {
	this.publicMethodsOnly = true;
	Assert.notEmpty(annotationParsers, "At least one TransactionAnnotationParser needs to be specified");
	this.annotationParsers = annotationParsers;
}

可以看到他帮我们创建除了事务注解解析器,进入解析器j看解析的是个啥(看返回值):

public interface TransactionAttribute extends TransactionDefinition {

	/**
	 * Return a qualifier value associated with this transaction attribute.
	 * <p>This may be used for choosing a corresponding transaction manager
	 * to process this specific transaction.
	 * @since 3.0
	 */
	@Nullable
	String getQualifier();

	/**
	 * Should we roll back on the given exception?
	 * @param ex the exception to evaluate
	 * @return whether to perform a rollback or not
	 */
	boolean rollbackOn(Throwable ex);

}

到了这里边应该就很清楚了,解析的就是@Transcation注解中的属性。(看继承关系)

public interface TransactionDefinition {

	int PROPAGATION_REQUIRED = 0;

	int PROPAGATION_SUPPORTS = 1;

	int PROPAGATION_MANDATORY = 2;

	int PROPAGATION_REQUIRES_NEW = 3;

	int PROPAGATION_NOT_SUPPORTED = 4;
	
	int PROPAGATION_NESTED = 6;

	int ISOLATION_DEFAULT = -1;

	int ISOLATION_READ_UNCOMMITTED = 1;  // same as java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;

	int ISOLATION_READ_COMMITTED = 2;  // same as java.sql.Connection.TRANSACTION_READ_COMMITTED;

	int ISOLATION_REPEATABLE_READ = 4;  // same as java.sql.Connection.TRANSACTION_REPEATABLE_READ;

	int ISOLATION_SERIALIZABLE = 8;  // same as java.sql.Connection.TRANSACTION_SERIALIZABLE;


	default int getPropagationBehavior() {
		return PROPAGATION_REQUIRED;
	}

	default int getIsolationLevel() {
		return ISOLATION_DEFAULT;
	}

	default int getTimeout() {
		return TIMEOUT_DEFAULT;
	}

	default boolean isReadOnly() {
		return false;
	}

	@Nullable
	default String getName() {
		return null;
	}
	
	static TransactionDefinition withDefaults() {
		return StaticTransactionDefinition.INSTANCE;
	}

}

所以通过上边的流程我们就能知道,TranscationAttributeSource就是帮助我们对@Transcation进行解析,让容器知道配置了哪些东西。
接下来就是BeanFactoryTransactionAttributeSourceAdvisor将事务代理对象注入到容器中(事务代理对象由事务解析器和事务的拦截器组成)

public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

	@Nullable
	private TransactionAttributeSource transactionAttributeSource;

	private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		@Override
		@Nullable
		protected TransactionAttributeSource getTransactionAttributeSource() {
			return transactionAttributeSource;
		}
	};


	/**
	 * Set the transaction attribute source which is used to find transaction
	 * attributes. This should usually be identical to the source reference
	 * set on the transaction interceptor itself.
	 * @see TransactionInterceptor#setTransactionAttributeSource
	 */
	public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
		this.transactionAttributeSource = transactionAttributeSource;
	}

	/**
	 * Set the {@link ClassFilter} to use for this pointcut.
	 * Default is {@link ClassFilter#TRUE}.
	 */
	public void setClassFilter(ClassFilter classFilter) {
		this.pointcut.setClassFilter(classFilter);
	}

	@Override
	public Pointcut getPointcut() {
		return this.pointcut;
	}

}
public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
    @Nullable
    private String adviceBeanName;
    @Nullable
    private BeanFactory beanFactory;
    @Nullable
    private transient volatile Advice advice;
    private transient volatile Object adviceMonitor = new Object();

    public AbstractBeanFactoryPointcutAdvisor() {
    }

    public void setAdviceBeanName(@Nullable String adviceBeanName) {
        this.adviceBeanName = adviceBeanName;
    }

    @Nullable
    public String getAdviceBeanName() {
        return this.adviceBeanName;
    }

    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
        this.resetAdviceMonitor();
    }

    private void resetAdviceMonitor() {
        if (this.beanFactory instanceof ConfigurableBeanFactory) {
            this.adviceMonitor = ((ConfigurableBeanFactory)this.beanFactory).getSingletonMutex();
        } else {
            this.adviceMonitor = new Object();
        }

    }

    public void setAdvice(Advice advice) {
        synchronized(this.adviceMonitor) {
            this.advice = advice;
        }
    }

    public Advice getAdvice() {
        Advice advice = this.advice;
        if (advice != null) {
            return advice;
        } else {
            Assert.state(this.adviceBeanName != null, "'adviceBeanName' must be specified");
            Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
            if (this.beanFactory.isSingleton(this.adviceBeanName)) {
                advice = (Advice)this.beanFactory.getBean(this.adviceBeanName, Advice.class);
                this.advice = advice;
                return advice;
            } else {
                synchronized(this.adviceMonitor) {
                    advice = this.advice;
                    if (advice == null) {
                        advice = (Advice)this.beanFactory.getBean(this.adviceBeanName, Advice.class);
                        this.advice = advice;
                    }

                    return advice;
                }
            }
        }
    }
}

看了上边就应该可以清楚切入点是什么,切对象是什么的。
最后就来说一下剩下的事务拦截器TransactionInterceptor

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {

	@Override
	@Nullable
	public Object invoke(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);
	}

}

这边只保留了最重要的invoke方法,也就是代理对象最后要执行的方法。里边就是事务执行和事务回滚过程。(可以回到上边)
注意:重点来了:
原理讲的差不多了,就来说一下使用事务注解时应该注意的地方。
·所以,所以如果你再方法中有try catch处理,那么try里边的代码块就脱离了事务的管理,如果要事务生效就必须在catch中throw RuntimeException
·上边是第一,另外方法不是 public的 – 该异常一般情况都会被编译器帮忙识别,看官方文档描述

When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.

·另外还需注意:自身调用问题。

@Service
public class OrderServiceImpl implements OrderService {
    @Transactional
    public void update(Order order) {
        updateOrder(order); 
   }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateOrder(Order order) {
        // update order;
    }
}

发生了自身调用,就调该类自己的方法,而没有经过 Spring 的代理类,默认只有在外部调用事务才会生效
·最后:异常类型错误或格式配置错误,默认触发事务回滚的异常是运行时异常。如果你想在除了运行时异常外其他异常也回滚的时候就需要给事务注解配置rollbackException参数->直接Exception.class就好了
肝,累死了,整理不易,如果感觉有帮助就给个三连。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
04-26
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

new_repo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值