开启Spring事务本质上就是增加了一个Advisor,在使用@EnableTransactionManagement注解来开启Spring事务时,该注解代理的功能就是向Spring容器中添加了两个Bean
- @Import(TransactionManagementConfigurationSelector.class)
- public @interface EnableTransactionManagement { ... }
-
-
- /**
- * Selects which implementation of {@link AbstractTransactionManagementConfiguration}
- * should be used based on the value of {@link EnableTransactionManagement#mode} on the
- * importing {@code @Configuration} class.
- *
- * @author Chris Beams
- * @author Juergen Hoeller
- * @since 3.1
- * @see EnableTransactionManagement
- * @see ProxyTransactionManagementConfiguration
- * @see TransactionManagementConfigUtils#TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME
- * @see TransactionManagementConfigUtils#JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME
- */
- public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector
{ -
- /**
- * 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:
- // 默认是PROXY
- return new String[] {AutoProxyRegistrar.class.getName(),
- ProxyTransactionManagementConfiguration.class.getName()};
- case ASPECTJ:
- // 表示不用动态代理技术,用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);
- }
-
- }
1、AutoProxyRegistrar
向Spring容器中注册了一个InfrastructureAdvisorAutoProxyCreator的Bean
InfrastructureAdvisorAutoProxyCreator 继承了AbstractAdvisorAutoProxyCreator
主要作用:开启自动代理
在初始化后寻找Advisor类型的Bean,并检查当前Bean是否有匹配的Advisor,是否需要动态代理创建代理对象
- /**
- * Registers an auto proxy creator against the current {@link BeanDefinitionRegistry}
- * as appropriate based on an {@code @Enable*} annotation having {@code mode} and
- * {@code proxyTargetClass} attributes set to the correct values.
- *
- * @author Chris Beams
- * @since 3.1
- * @see org.springframework.cache.annotation.EnableCaching
- * @see org.springframework.transaction.annotation.EnableTransactionManagement
- */
- public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
-
- private final Log logger = LogFactory.getLog(getClass());
-
- /**
- * Register, escalate, and configure the standard auto proxy creator (APC) against the
- * given registry. Works by finding the nearest annotation declared on the importing
- * {@code @Configuration} class that has both {@code mode} and {@code proxyTargetClass}
- * attributes. If {@code mode} is set to {@code PROXY}, the APC is registered; if
- * {@code proxyTargetClass} is set to {@code true}, then the APC is forced to use
- * subclass (CGLIB) proxying.
- *
Several {@code @Enable*} annotations expose both {@code mode} and
- * {@code proxyTargetClass} attributes. It is important to note that most of these
- * capabilities end up sharing a {@linkplain AopConfigUtils#AUTO_PROXY_CREATOR_BEAN_NAME
- * single APC}. For this reason, this implementation doesn't "care" exactly which
- * annotation it finds -- as long as it exposes the right {@code mode} and
- * {@code proxyTargetClass} attributes, the APC can be registered and configured all
- * the same.
- */
- @Override
- public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
- boolean candidateFound = false;
- Set
annTypes = importingClassMetadata.getAnnotationTypes(); - for (String annType : annTypes) {
- AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
- if (candidate == null) {
- continue;
- }
- 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) {
- // 注册InfrastructureAdvisorAutoProxyCreator,才可以Bean进行AOP
- AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
- if ((Boolean) proxyTargetClass) {
- // 设置InfrastructureAdvisorAutoProxyCreator的proxyTargetClass为true
- AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
- return;
- }
- }
- }
- }
- if (!candidateFound && logger.isInfoEnabled()) {
- String name = getClass().getSimpleName();
- 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));
- }
- }
-
- }
-
- // AopConfigUtils#registerAutoProxyCreatorIfNecessary
- public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
- return registerAutoProxyCreatorIfNecessary(registry, null);
- }
-
- // AopConfigUtils#registerAutoProxyCreatorIfNecessary
- public static BeanDefinition registerAutoProxyCreatorIfNecessary(
- BeanDefinitionRegistry registry, @Nullable Object source) {
- return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
- }
-
- // AopConfigUtils#forceAutoProxyCreatorToUseClassProxying
- public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
- // AUTO_PROXY_CREATOR_BEAN_NAME = "org.springframework.aop.config.internalAutoProxyCreator"
- if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
- BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
- definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
- }
- }
2、ProxyTransactionManagementConfiguration
是一个配置类,内部定义了三个Bean:
BeanFactoryTransactionAttributeSourceAdvisor:一个Advisor
AnnotationTransactionAttributeSource:相当于BeanFactoryTransactionAttributeSourceAdvisor中的Pointcut,判断某个类或者方法上面是否存在@Transactional注解,注意这里并没有解析
TransactionInterceptor:相当于BeanFactoryTransactionAttributeSourceAdvisor中的 Advice,当某个类中存在@Transactional注解,就会产生一个代理对象作为Bean,在执行代理对象的某个方法时会进入到TransactionInterceptor的invoke()方法中
invoke()方法里面就会创建数据库连接、关闭自动提交、事务提交和回滚等
- /**
- * {@code @Configuration} class that registers the Spring infrastructure beans
- * necessary to enable proxy-based annotation-driven transaction management.
- *
- * @author Chris Beams
- * @author Sebastien Deleuze
- * @since 3.1
- * @see EnableTransactionManagement
- * @see TransactionManagementConfigurationSelector
- */
- @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.
getNumber("order")); - }
- return advisor;
- }
-
- @Bean
- @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
- public TransactionAttributeSource transactionAttributeSource() {
- // AnnotationTransactionAttributeSource中定义了一个Pointcut
- // 并且AnnotationTransactionAttributeSource可以用来解析@Transactional注解,并得到一个RuleBasedTransactionAttribute对象
- 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;
- }
-
- }
InfrastructureAdvisorAutoProxyCreator也是一个BeanPostProcessor(最终实现SmartInstantiationAwareBeanPostProcessor),在Bean的生命周期初始化后步骤时,会去判断是否需要创建代理对象
判断依据:当前Bean和BeanFactoryTransactionAttributeSourceAdvisor匹配,简单点就是当前Bean的类或者方法上面有没有@Transactional注解,有就匹配
在代理对象执行某个方法时,会再次判断当前执行方法和BeanFactoryTransactionAttributeSourceAdvisor是否匹配,如果匹配则执行该Advisor中的TransactionInterceptor的invoke()方法,执行流程:
(再次判断是考虑到一个类中可能有多个方法,有的方法有@Transactional注解,有的没有)
1、利用所配置的PlatformTransactionManager事务管理器新建一个数据库连接,注意TransactionManager有限制的必须是PlatformTransactionManager,然后会生成一个joinpointIdentification作为事务的名字
2、修改数据库连接的autocommit为false
3、执行MethodInvocation.proceed()方法,简单理解就是执行业务方法,其中就会执行sql
4、如果没有抛异常,则提交,执行完finally中的方法后再进行提交
5、如果抛了异常,则回滚,执行完finally中的方法后再抛出异常
开发过程中,经常会出现一个方法调用另外一个方法,那么就涉及到了多种场景。比如多个方法需要在同一个事务中执行;每个方法要在单独的事务中执行;有的方法需要事务,有的不需要事务;还有很多更复杂情况。Spring为了支持各种场景,也就有了Spring事务传播机制
场景分析,假设a()方法在事务执行中,调用b()方法需要开启一个新事务执行:
1、首先,代理对象执行a()方法前,先利用事务管理器新建一个数据库连接a
2、将数据库连接a的autocommit改为false
3、把数据库连接a设置到ThreadLocal中
4、执行a()方法中的sql
5、执行a()方法过程中,调用了b()方法(注意用代理对象调用b()方法)
a)代理对象执行b()方法前,判断出来了当前线程中已经存在一个数据库连接a了,表示当前线程其实已经拥有一个Spring事务了,则进行挂起
b)挂起就是把ThreadLocal中的数据库连接a从ThreadLocal中移除,并放入一个挂起资源对象中(就是事务同步管理器:TransactionSynchronizationManager)
c)挂起完成后,再次利用事务管理器新建一个数据库连接b
d)将数据库连接b的autocommit改为false
e)把数据库连接b设置到ThreadLocal中
f)执行b()方法中的sql
g)b()方法正常执行完,则从ThreadLocal中拿到数据库连接b进行提交
h)提交之后会恢复所挂起的数据库连接a,这里的恢复,其实只是把在挂起资源对象中所保存的数据库连接a再次设置到ThreadLocal中
6、a()方法正常执行完,则从ThreadLocal中拿到数据库连接a进行提交
过程核心:在执行某个方法时,判断当前是否已经存在一个事务,就是判断当前线程的ThreadLocal中是否存在一个数据库连接对象,如果存在则表示已经存在一个事务了。
代理对象执行方法时,源码invoke入口:
- // TransactionInterceptor#invoke
- 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, new CoroutinesInvocationCallback() {
- @Override
- @Nullable
- public Object proceedWithInvocation() throws Throwable {
- // 执行后续的Interceptor,以及被代理的方法
- return invocation.proceed(); // test() sql
- }
- @Override
- public Object getTarget() {
- return invocation.getThis();
- }
- @Override
- public Object[] getArguments() {
- return invocation.getArguments();
- }
- });
- }
-
- @Override
- @Nullable
- public Object proceed() throws Throwable {
-
- // We start with an index of -1 and increment early.
- // currentInterceptorIndex初始值为-1,每调用一个interceptor就会加1
- // 当调用完了最后一个interceptor后就会执行被代理方法
- if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
- return invokeJoinpoint();
- }
-
- // currentInterceptorIndex初始值为-1
- Object interceptorOrInterceptionAdvice =
- this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
-
- // 当前interceptor是InterceptorAndDynamicMethodMatcher,则先进行匹配,匹配成功后再调用该interceptor
- // 如果没有匹配则递归调用proceed()方法,调用下一个interceptor
- if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
- // Evaluate dynamic method matcher here: static part will already have
- // been evaluated and found to match.
- InterceptorAndDynamicMethodMatcher dm =
- (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
- Class> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
- // 动态匹配,根据方法参数匹配
- if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
- return dm.interceptor.invoke(this);
- }
- else {
- // Dynamic matching failed.
- // Skip this interceptor and invoke the next in the chain.
- // 不匹配则执行下一个MethodInterceptor
- return proceed();
- }
- }
- else {
-
- // It's an interceptor, so we just invoke it: The pointcut will have
- // been evaluated statically before this object was constructed.
- // 直接调用MethodInterceptor,传入this,在内部会再次调用proceed()方法进行递归
- // 比如MethodBeforeAdviceInterceptor
- return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
- }
- }
TransactionInterceptor#invokeWithinTransaction:
- /**
- * 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 and
- * {@link ReactiveTransactionManager} implementations for reactive return types.
- * @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.
- // TransactionAttribute就是@Transactional中的配置
- TransactionAttributeSource tas = getTransactionAttributeSource();
- // 获取@Transactional注解中的属性值
- final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
-
- // 返回Spring容器中类型为TransactionManager的Bean对象
- final TransactionManager tm = determineTransactionManager(txAttr);
-
- // ReactiveTransactionManager用得少,并且它只是执行方式是响应式的,原理流程和普通的是一样的
- if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
- ... ...
- }
-
- // 把tm强制转换为PlatformTransactionManager,所以我们在定义时得定义PlatformTransactionManager类型
- PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
-
- // joinpoint的唯一标识,就是当前在执行的方法名字
- final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
-
- // CallbackPreferringPlatformTransactionManager表示拥有回调功能的PlatformTransactionManager,也不常用
- if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
- // Standard transaction demarcation with getTransaction and commit/rollback calls.
- // 如果有必要就创建事务,这里就涉及到事务传播机制的实现了
- // TransactionInfo表示一个逻辑事务,比如两个逻辑事务属于同一个物理事务
- 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.
- // 执行下一个Interceptor或被代理对象中的方法
- retVal = invocation.proceedWithInvocation(); // test() sql
- }
- 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();
- ... ...
- }
- }
-
- /**
- * 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,但是TransactionStatus中有一个属性代表当前逻辑事务底层的物理事务是不是新的
- 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");
- }
- }
- }
-
- // 返回一个TransactionInfo对象,表示得到了一个事务,可能是新创建的一个事务,也可能是拿到的已有的事务
- return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
- }
关键方法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 {
-
- // Use defaults if no transaction definition given.
- TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
-
- // 得到一个新的DataSourceTransactionObject对象
- // new DataSourceTransactionObject txObject
- Object transaction = doGetTransaction();
- boolean debugEnabled = logger.isDebugEnabled();
-
- // transaction.getConnectionHolder().isTransactionActive()
- if (isExistingTransaction(transaction)) {
- // Existing transaction found -> check propagation behavior to find out how to behave.
- return handleExistingTransaction(def, transaction, debugEnabled);
- }
-
- // Check definition settings for new transaction.
- if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
- throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
- }
-
- // No existing transaction found -> check propagation behavior to find out how to proceed.
- // 手动开启事务的传播机制
- if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
- throw new IllegalTransactionStateException(
- "No existing transaction found for transaction marked with propagation 'mandatory'");
- }
- // 在当前Thread中没有事务的前提下,以下三个是等价的
- else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
- def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
- def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
- // 没有事务需要挂起,不过TransactionSynchronization有可能需要挂起
- // suspendedResources表示当前线程被挂起的资源持有对象(数据库连接、TransactionSynchronization)
- SuspendedResourcesHolder suspendedResources = suspend(null);
- if (debugEnabled) {
- logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
- }
- try {
- // 开启事务后,transaction中就会有数据库连接了,并且isTransactionActive为true
- // 并返回TransactionStatus对象,该对象保存了很多信息,包括被挂起的资源
- return startTransaction(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);
- }
- boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
- return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
- }
- }
-
-
- /**
- * 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");
- }
- // 把当前事务挂起,其中就会把数据库连接对象从ThreadLocal中移除
- 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 {
- return startTransaction(definition, transaction, debugEnabled, suspendedResources);
- }
- catch (RuntimeException | Error beginEx) {
- resumeAfterBeginException(transaction, suspendedResources, beginEx);
- throw beginEx;
- }
- }
-
- 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);
- // 创建一个savepoint
- 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.
- return startTransaction(definition, transaction, debugEnabled, null);
- }
- }
-
- // 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");
- }
- }
- }
-
- // 如果依然是Propagation.REQUIRED
- boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
- return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
- }
开启事务startTransaction:
- /**
- * Start a new transaction.
- */
- private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
-
- // 是否开启一个新的TransactionSynchronization
- boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
-
- // 开启的这个事务的状态信息:
- // 事务的定义、用来保存数据库连接的对象、是否是新事务,是否是新的TransactionSynchronization
- DefaultTransactionStatus status = newTransactionStatus(
- definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
-
- // 开启事务
- doBegin(transaction, definition);
-
- // 如果需要新开一个TransactionSynchronization,就把新创建的事务的一些状态信息设置到TransactionSynchronizationManager中
- prepareSynchronization(status, definition);
- return status;
- }
-
- // DataSourceTransactionManager#doBegin
- @Override
- protected void doBegin(Object transaction, TransactionDefinition definition) {
- DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
- Connection con = null;
-
- try {
-
- // 如果当前线程中所使用的DataSource还没有创建过数据库连接,就获取一个新的数据库连接
- 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();
-
- // 根据@Transactional注解中的设置,设置Connection的readOnly与隔离级别
- 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).
- // 设置autocommit为false
- 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.
- // 把新建的数据库连接设置到resources中,resources就是一个ThreadLocal
- 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);
- }
- }
以非事务方式运行:表示以非Spring事务运行,表示在执行这个方法时,Spring事务管理器不会去建立数据库连接,执行sql时,由Mybatis或JdbcTemplate自己来建立数据库连接来执行 sql。
事务1内部调用事务2场景,无异常
- @Component
- public class UserService
- {
- @Autowired
- private UserService userService;
-
- @Transactional
- public void test()
- {
- // test方法中的sql
- userService.a();
- }
- @Transactional
- public void a()
- {
- // a方法中的sql
- }
- }
默认情况下传播机制为REQUIRED,表示当前如果没有事务则新建一个事务,如果有事务则在当前事务中执行。
执行流程:
1、新建一个数据库连接conn
2、设置conn的autocommit为false
3、执行test方法中的sql
4、执行a方法中的sql
5、执行conn的commit()方法进行提交
事务1内部调用事务2场景,事务1内部有异常
- @Component
- public class UserService
- {
- @Autowired
- private UserService userService;
-
- @Transactional
- public void test()
- {
- // test方法中的sql
- userService.a();
- int result = 100/0;
- }
- @Transactional
- public void a()
- {
- // a方法中的sql
- }
- }
执行流程:
1、新建一个数据库连接conn
2、设置conn的autocommit为false
3、执行test方法中的sql
4、执行a方法中的sql
5、抛出异常
6、执行conn的rollback()方法进行回滚,所以两个方法中的sql都会回滚掉
事务1内部调用事务2场景,事务2内部有异常
- @Component
- public class UserService
- {
- @Autowired
- private UserService userService;
-
- @Transactional
- public void test()
- {
- // test方法中的sql
- userService.a();
- }
- @Transactional
- public void a()
- {
- // a方法中的sql
- int result = 100/0;
- }
- }
执行流程:
1、新建一个数据库连接conn
2、设置conn的autocommit为false
3、执行test方法中的sql
4、执行a方法中的sql
5、抛出异常
6、执行conn的rollback()方法进行回滚,所以两个方法中的sql都会回滚掉
对于事务1而言,userService.a(); 这个方法的调用抛出了异常,所以事务1也要回滚
- @Component
- public class UserService
- {
- @Autowired
- private UserService userService;
-
- @Transactional
- public void test()
- {
- // test方法中的sql
- userService.a();
- }
- @Transactional(propagation = Propagation.REQUIRES_NEW)
- public void a()
- {
- // a方法中的sql
- int result = 100/0;
- }
- }
执行流程:
1、新建一个数据库连接conn
2、设置conn的autocommit为false
3、执行test方法中的sql
4、又新建一个数据库连接conn2
5、执行a方法中的sql
6、抛出异常
7、执行conn2的rollback()方法进行回滚
8、继续抛异常,对于test()方法而言,它会接收到一个异常,然后抛出
9、执行conn的rollback()方法进行回滚,最终还是两个方法中的sql都回滚了
正常情况下,a()调用b()方法时,如果b()方法抛了异常,但是在a()方法捕获了,那么a()的事务还是会正常提交的,但是有的时候,我们捕获异常可能仅仅只是不把异常信息返回给客户端,而是为了返回一些更友好的错误信息,而这个时候,我们还是希望事务能回滚的,那这个时候就得告诉Spring把当前事务回滚掉,做法就是:
- @Transactional
- public void test()
- {
- // 执行sql
- try
- {
- b();
- } catch (Exception e)
- {
- // 构造友好的错误信息返回
- TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
- }
- }
-
- public void b() throws Exception
- {
- throw new Exception();
- }
事务仍然回滚,捕获异常是为了给客户端更好的提示
Spring事务有可能会提交,回滚、挂起、恢复,所以Spring事务提供了一种机制,可以让程序员来监听当前Spring事务所处于的状态。
- @Component
- public class UserService
- {
- @Autowired
- private JdbcTemplate jdbcTemplate;
-
- @Autowired
- private UserService userService;
-
- @Transactional
- public void test()
- {
- TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization()
- {
- @Override
- public void suspend()
- {
- System.out.println("test被挂起了");
- }
-
- @Override
- public void resume()
- {
- System.out.println("test被恢复了");
- }
-
- @Override
- public void beforeCommit(boolean readOnly)
- {
- System.out.println("test准备要提交了");
- }
-
- @Override
- public void beforeCompletion()
- {
- System.out.println("test准备要提交或回滚了");
- }
-
- @Override
- public void afterCommit()
- {
- System.out.println("test提交成功了");
- }
-
- @Override
- public void afterCompletion(int status)
- {
- System.out.println("test提交或回滚成功了");
- }
- });
- jdbcTemplate.execute("insert into t1 values(1,1,1,1,'1')");
- System.out.println("test");
- userService.a();
- }
-
- @Transactional(propagation = Propagation.REQUIRES_NEW)
- public void a()
- {
- TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization()
- {
- @Override
- public void suspend()
- {
- System.out.println("a被挂起了");
- }
-
- @Override
- public void resume()
- {
- System.out.println("a被恢复了");
- }
-
- @Override
- public void beforeCommit(boolean readOnly)
- {
- System.out.println("a准备要提交了");
- }
-
- @Override
- public void beforeCompletion()
- {
- System.out.println("a准备要提交或回滚了");
- }
-
- @Override
- public void afterCommit()
- {
- System.out.println("a提交成功了");
- }
-
- @Override
- public void afterCompletion(int status)
- {
- System.out.println("a提交或回滚成功了");
- System.out.println("a提交或回滚成功了");
- }
- });
- jdbcTemplate.execute("insert into t1 values(2,2,2,2,'2')");
- System.out.println("a");
- }
- }