Spring源码-@EnableTransactionManagement方式事务实现分析(下)

目录

一、BeanFactoryTransactionAttributeSourceAdvisor

二、TransactionInterceptor

1、解析@Transactional上的标签属性

2、根据属性获取事务管理器(determineTransactionManager)

3、获取方法唯一标识

4、声明式事务(或编程式事务)

1)、创建事务(如果需要,根据配置解析判断)

2)、try:执行事务增强的方法

3)、catch:异常进行处理(如果必要进行回滚)

4)、finally:清除事务信息

5)、提交事务,组装返回信息(commitTransactionAfterReturning)


    之前先分析 TransactionAttributeSource,其就是一个解析@Transactional标签的解析器的组装容器,相当于工具或者解析标签功能。TransactionInterceptor是真正做事的,而BeanFactoryTransactionAttrbuteSourceAdvisor则是协调容器。

一、BeanFactoryTransactionAttributeSourceAdvisor

public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

	@Nullable
	private TransactionAttributeSource transactionAttributeSource;

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

    初始化了一个TransactionAttributeSourcePointcut 用于match时使用。另外是一个Spring Aop的实现,结构如下:

实现Aop的getAdvisor方法,是在父类AbstractBeanFactoryPointcutAdvisor中完成,如下:

@Override
public Advice getAdvice() {
    Advice advice = this.advice;
    if (advice != null) {
        return advice;
    }

    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)) {
        // Rely on singleton semantics provided by the factory.
        advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
        this.advice = advice;
        return advice;
    }
    else {
        // No singleton guarantees from the factory -> let's lock locally but
        // reuse the factory's singleton lock, just in case a lazy dependency
        // of our advice bean happens to trigger the singleton lock implicitly...
        synchronized (this.adviceMonitor) {
            advice = this.advice;
            if (advice == null) {
                advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
                this.advice = advice;
            }
            return advice;
        }
    }
}

    因为在初始化时,设置了advisor为我们传入的TransactionInterceptor,所以干活的在下面进行分析。

 

二、TransactionInterceptor

实现了MethodInterceptor接口,那么则主要实现逻辑为invoke方法。何时回调在BeanFactoryTransactionAttrbuteSourceAdvisor中已经确定。

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);
}
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
                                         final InvocationCallback invocation) throws Throwable {

    if (this.reactiveAdapterRegistry != null) {
        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) {
            return new ReactiveTransactionSupport(adapter).invokeWithinTransaction(method, targetClass, invocation);
        }
    }

    // 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;
        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 (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 {
        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 {
                    Object retVal = invocation.proceedWithInvocation();
                    if (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);
                }
            });

            // 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;
        }
    }
}

1、解析@Transactional上的标签属性

解析器和解析原理之前在AnnotationTransactionAttributeSource分析过了

TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? 
    tas.getTransactionAttribute(method, targetClass) : null);

2、根据属性获取事务管理器(determineTransactionManager)

final PlatformTransactionManager tm = determineTransactionManager(txAttr);
protected PlatformTransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
    // Do not attempt to lookup tx manager if no tx attributes are set
    if (txAttr == null || this.beanFactory == null) {
        return asPlatformTransactionManager(getTransactionManager());
    }

    String qualifier = txAttr.getQualifier();
    if (StringUtils.hasText(qualifier)) {
        return determineQualifiedTransactionManager(this.beanFactory, qualifier);
    }
    else if (StringUtils.hasText(this.transactionManagerBeanName)) {
        return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
    }
    else {
        PlatformTransactionManager defaultTransactionManager = asPlatformTransactionManager(getTransactionManager());
        if (defaultTransactionManager == null) {
            defaultTransactionManager = asPlatformTransactionManager(
                    this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY));
            if (defaultTransactionManager == null) {
                defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
                this.transactionManagerCache.putIfAbsent(
                        DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
            }
        }
        return defaultTransactionManager;
    }
}

1)、先获取qualifier值,SpringTransactionAnnotationParser在解析的时候,将@Transactional上的value值解析为该字段。所以第一优先级是配置的时候自己知道管理器。

public @interface Transactional {

	/**
	 * Alias for {@link #transactionManager}.
	 * @see #transactionManager
	 */
	@AliasFor("transactionManager")
	String value() default "";
}

2)、第二优先级是获取TransactionInterceptor上的 transactionManagerBeanName字段,我们初始化时候没有指定并且后续也没有进行设置。

3)、所以一般会走最后一种情况。先分享TransactionInterceptor中的txManager是哪里设置的。前面ProxyTransactionManagementConfiguration中初始化bean的时候设置了,而其txManager是ProxyTransactionManagementConfiguration的getBean的时候从ImportAwear接口回调注入进来的。

当然如果是空的就没有注入进来,那么先从本地缓存拿,为空则从BeanFactory中获取 PlatformTransactionManager类型的txmanager,并放入缓存。

3、获取方法唯一标识

如: userService.getUser。

private String methodIdentification(Method method, @Nullable Class<?> targetClass,
                                    @Nullable TransactionAttribute txAttr) {

    String methodIdentification = methodIdentification(method, targetClass);
    if (methodIdentification == null) {
        if (txAttr instanceof DefaultTransactionAttribute) {
            methodIdentification = ((DefaultTransactionAttribute) txAttr).getDescriptor();
        }
        if (methodIdentification == null) {
            methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
        }
    }
    return methodIdentification;
}

还是一样的优先级方式,

1)、有没有进行重新父类的获取方式,显然没有。

2)、获取descriptor属性

SpringTransactionAnnotationParser解析的是 RuleBasedTransactionAttribute虽然是 DefaultTransactionAttribute 类型,但是没有进行赋值。

3)、最后最近反射获取

4、声明式事务(或编程式事务)

txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager) 为声明式事务,否则为编程式事务(不进行分析了)。

1)、创建事务(如果需要,根据配置解析判断)

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

1、包装事务

    如果事务属性不为null,并且名称为null。解析的时候是没有设置名称的,所以会将事务属性 RuleBasedTransactionAttribute包装成 DelegatingTransactionAttribute 类型,增加功能方便后面使用。

2、获取事务

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
        throws TransactionException {

    // Use defaults if no transaction definition given.
    TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

    Object transaction = doGetTransaction();
    boolean debugEnabled = logger.isDebugEnabled();

    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'");
    }
    else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
            def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
            def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
        SuspendedResourcesHolder suspendedResources = suspend(null);
        if (debugEnabled) {
            logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
        }
        try {
            boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
            DefaultTransactionStatus status = newTransactionStatus(
                    def, transaction, true, newSynchronization, debugEnabled, suspendedResources);
            doBegin(transaction, def);
            prepareSynchronization(status, def);
            return status;
        }
        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);
    }
}

1)、根据不同的事务管理器获取一个事务,如datasource类型:

protected Object doGetTransaction() {
    DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject();
    txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
    ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.dataSource);
    txObject.setConnectionHolder(conHolder, false);
    return txObject;
}

2)、判断事务是否已经存在,

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");
        }
        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 {
            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 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);
            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.
            boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
            DefaultTransactionStatus status = newTransactionStatus(
                    definition, transaction, true, newSynchronization, debugEnabled, null);
            doBegin(transaction, definition);
            prepareSynchronization(status, definition);
            return status;
        }
    }

    // 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");
            }
        }
    }
    boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}

如果存在,则根据当前@Transactional中配置的Propagation事务传播行为进行处理:

PROPAGATION_NEVER: 直接抛异常

PROPAGATION_NOT_SUPPORTED: 不应该运行在事务中,如果存在当前事务,在该方法运行期间,当前事务将被挂起

PROPAGATION_REQUIRES_NEW:必须运行在它自己的事务中。一个新的事务将被启动,如果存在当前事务,在该方法执行期间,当前事务会被挂起(如果一个事务已经存在,则先将这个存在的事务挂起)

PROPAGATION_NESTED:如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行

默认事务传播行为为:REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED)

 

3、处理事务信息

protected final DefaultTransactionStatus prepareTransactionStatus(
		TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,
		boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {

	DefaultTransactionStatus status = newTransactionStatus(
			definition, transaction, newTransaction, newSynchronization, debug, suspendedResources);
	prepareSynchronization(status, definition);
	return status;
}

初始化一个 DefaultTransactionStatus类型的 TransactionStatus,开启事务进行处理,

doBegin(transaction, definition);

默认是否newTransaction为false,

则不进行sync,就进行返回了。其他的回头再分析。。。

2)、try:执行事务增强的方法

retVal = invocation.proceedWithInvocation();

    执行aop的round方法

3)、catch:异常进行处理(如果必要进行回滚)

protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
	if (txInfo != null && txInfo.getTransactionStatus() != null) {
		if (logger.isTraceEnabled()) {
			logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
					"] after exception: " + ex);
		}
		if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
			try {
				txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
			}
			catch (TransactionSystemException ex2) {
				logger.error("Application exception overridden by rollback exception", ex);
				ex2.initApplicationException(ex);
				throw ex2;
			}
			catch (RuntimeException | Error ex2) {
				logger.error("Application exception overridden by rollback exception", ex);
				throw ex2;
			}
		}
		else {
			// We don't roll back on this exception.
			// Will still roll back if TransactionStatus.isRollbackOnly() is true.
			try {
				txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
			}
			catch (TransactionSystemException ex2) {
				logger.error("Application exception overridden by commit exception", ex);
				ex2.initApplicationException(ex);
				throw ex2;
			}
			catch (RuntimeException | Error ex2) {
				logger.error("Application exception overridden by commit exception", ex);
				throw ex2;
			}
		}
	}
}

1)、判断是否满足回滚条件

若没有配置@Transactional上的 rollbackFor、rollbackForClassName、noRollbackFor、noRollbackForClassName信息,则是父类 DefaultTransactionAttribute 上的rollbackOn方法。

public boolean rollbackOn(Throwable ex) {
	return (ex instanceof RuntimeException || ex instanceof Error);
}

2)、进行回滚或者提交

txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());

4)、finally:清除事务信息

protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
	if (txInfo != null) {
		txInfo.restoreThreadLocalStatus();
	}
}


5)、提交事务,组装返回信息(commitTransactionAfterReturning)

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        if (logger.isTraceEnabled()) {
            logger.trace("Completing transaction for [" + 
                txInfo.getJoinpointIdentification() + "]");
        }
    txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
    }
}

 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
@EnableTransactionManagement注解的作用是开启Spring事务管理功能。在Spring Boot项目中,通常将该注解配置在启动类上,它的效果等同于在一般的Spring项目中配置<tx:annotation-driven />。开启事务支持后,可以在访问数据库的Service方法上添加@Transactional注解,从而使得这些方法支持事务。当@EnableTransactionManagement注解放在类上时,表示该类中的所有方法都支持事务。 @EnableTransactionManagement的作用是为了简化事务的配置,使得开发者可以更方便地使用事务管理功能。通过该注解,开发者无需手动配置事务管理器、事务通知器等,Spring会自动为其创建相应的Bean,并将其应用到需要事务管理的方法上。 @EnableTransactionManagement的使用可以提高代码的可读性和可维护性,同时也能够确保数据的一致性和完整性。通过使用@Transactional注解,可以将多个数据库操作作为一个事务进行管理,当其中任何一个操作失败时,整个事务会被回滚,保证数据的一致性。 范例:<<引用:spring-boot @EnableTransactionManagement 作用。该注解表示开启事务支持 在springboot项目中一般配置在启动类上 效果等同于一般spring中 xml配置的<tx:annotation-driven />。 开启事务支持后,然后在访问数据库的Service方法上添加注解 @Transactional 后当前方法将支持事务。 放在类上时 所有方法支持事务。>> @EnableTransactionManagement注解的作用是开启Spring事务管理功能。在Spring Boot项目中,通常将该注解配置在启动类上,它的效果等同于在一般的Spring项目中配置<tx:annotation-driven />。开启事务支持后,可以在访问数据库的Service方法上添加@Transactional注解,从而使得这些方法支持事务。当@EnableTransactionManagement注解放在类上时,表示该类中的所有方法都支持事务
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值