Spring源码分析(五) 事务全流程分析

news2024/11/22 21:52:10

Spring事务的基础知识

1、注解相关属性

@Transactional 注解的属性信息
name 当在配置文件中有多个 TransactionManager , 可以用该属性指定选择哪个事务管理器
propagation 事务的传播行为,默认值为 REQUIRED。
isolation 事务的隔离度,默认值采用 DEFAULT。
timeout 事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
read-only 指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。
rollback-for 用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔。
no-rollback- for 抛出 no-rollback-for 指定的异常类型,不回滚事务。

除此以外,@Transactional 注解也可以添加到类级别上。当把@Transactional 注解放在类级别时,表示所有该类的公共方法都配置相同的事务属性信息。见清单 2,EmployeeService 的所有方法都支持事务并且是只读。当类级别配置了@Transactional,方法级别也配置了@Transactional,应用程序会以方法级别的事务属性信息来管理事务,换言之,方法级别的事务属性信息会覆盖类级别的相关配置信息。

2、传播级别

介绍
Spring事务的传播级别描述的是多个使用了@Transactional注解的方法互相调用时,Spring对事务的处理。包涵的传播级别有:(在TransactionDefinition接口中定义)
7种事务传播行为如下:默认 propagation = PROPAGATION_REQUIRED

1.PROPAGATION_REQUIRED
  如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,这是最常见的选择,也是Spring默认的事务传播行为。
2.PROPAGATION_SUPPORTS
  支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
如果外围事务回滚,内部事务也要回滚。
3.PROPAGATION_MANDATORY
  支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
4.PROPAGATION_REQUIRES_NEW
  创建新事务,无论当前存不存在事务,都创建新事务。
5.PROPAGATION_NOT_SUPPORTED
  以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6.PROPAGATION_NEVER
  以非事务方式执行,如果当前存在事务,则抛出异常。
7.PROPAGATION_NESTED
  如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。
在这里插入图片描述

一、Spring事务开启入口

开启Spring事务很简单,首先在启动类上添加@EnableTransactionManagement注解,再注入一个PlatformTransactionManager事务管理器即可。

@Bean
public DataSourceTransactionManager dataSourceTransactionManager() {
    return new DataSourceTransactionManager(dataSource());
}

在开启了Spring事务功能,只需要在事务方法上加上@Transactional注解,该方法就会被Spring当作事务方法来处理,发生异常时自动回滚,无异常时自动提交事务。

1.1 @EnableTransactionManagement

@EnableTransactionManagement注解通过@Import引入了另一个配置TransactionManagentConfigurationSelector。
TransactionManangementConfigurationSelector在Spring中,Selector通常都是用来选择一些Bean,向容器注册BeanDefinition的(严格意义上Selector仅时选择过程,注册的具体过程是在ConfigurationClasspathPostProcessor解析时,调用ConfigurationClassParser触发)。主要的逻辑就是根据代理模式,注册不同的BeanDefinition。对Proxy的模式而言,注入的有两个:
AutoProxyRegistrar,ProxyTransactionManagementConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 开启Spring事务支持
// 通过@EnableTransactionManagement引入TransactionManagementConfigurationSelector组件,进而导入两个bean:
// a、AutoProxyRegistrar
// b、ProxyTransactionManagementConfiguration
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
 
	/**
	 * 使用JDK动态代理还是Cglib动态代理,默认是false,但前提是AdviceMode必须是PROXY才适用
	 */
	boolean proxyTargetClass() default false;
 
	/**
	 * 通知的模式,默认是PROXY,还有一种是ASPECTJ
	 */
	AdviceMode mode() default AdviceMode.PROXY;
 
	/**
     * 指定通知器的执行顺序
	 */
	int order() default Ordered.LOWEST_PRECEDENCE;
 
}

TransactionManagementConfigurationSelector是ImportSelector的子类,所以它必须重写ImportSelector#selectImports()方法,Spring会自动注册该方法返回的bean集合。

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
    @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);
    }
}

ransactionManagementConfigurationSelector类的目的主要是向Spring容器注册了两个bean:
1、AutoProxyRegistrar
往容器内注册InfrastructureAdvisorAutoProxyCreator非常关键的bean,基于Advisor创建bean代理对象,让bean拥有事务增强的能力。这个类之前在aop中介绍过,是bean后置处理器,会拦截所有bean的创建,对符合条件的bean创建代理。
总结就是:AutoProxyRegistrar的作用就是启用spring aop的功能,对符合条件的bean创建代理

2、ProxyTransactionManagementConfiguration
往容器内注册BeanFactoryTransactionAttributeSourceAdvisor以及依赖的bean,织入该Advisor的bean将拥有事务增强的能力。
总结就是在aop中添加事务拦截器TransactionInterceptor

由此可见,Spring事务是基于AOP实现的。AutoProxyRegistrar用来创建bean的代理对象,ProxyTransactionManagementConfiguration用来注册事务增强器。二者结合起来的效果就是:对@Transaction标注的bean创建代理对象,代理对象中通过TransactionInterceptor拦截器来实现事务管理的功能。

1.1.1 AutoProxyRegistrar

Registrar同样也是用来向容器注册Bean的,在Proxy的模式下,它会调用AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);向容器中注册InfrastructureAdvisorAutoProxyCreator。而这个类就是之前提到的AbstractAdvisorAutoProxyCreator的子类。

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
 
	private final Log logger = LogFactory.getLog(getClass());
 
	@Override
	// org.springframework.context.annotation.AutoProxyRegistrar.registerBeanDefinitions
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean candidateFound = false;
		Set<String> 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
		AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
 
					if ((Boolean) proxyTargetClass) {
						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));
		}
	}
 
}
 
// org.springframework.aop.config.AopConfigUtils#registerAutoProxyCreatorIfNecessary
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
    return registerAutoProxyCreatorIfNecessary(registry, null);
}
 
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
    BeanDefinitionRegistry registry, @Nullable Object source) {
    // 注册或者升级InfrastructureAdvisorAutoProxyCreator组件
    return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
a、 InfrastructureAdvisorAutoProxyCreator

主要作用是基于容器内的Advisor给需要被增强的bean创建代理对象。
它通过实现BeanPostProcessor接口,重写postProcessAfterInitialization()方法来增强bean,这个逻辑和AOP是一样的。
在这里插入图片描述

1.1.2 补充:如何判读是否需要被增强?

连接点是否需要被增强,是通过切点(Pointcut)来判断的,所以PointcutAdvisor接口会关联一个Pointcut

public interface PointcutAdvisor extends Advisor {

	/**
	 * 获取切点,判断方法是否要增强
	 */
	Pointcut getPointcut();

}

Pointcut用来判断方法是否需要被增强,所以会关联一个类过滤器ClassFilter和方法匹配器MethodMatcher:

public interface Pointcut {

	/**
	 * 先匹配类
	 */
	ClassFilter getClassFilter();

	/**
	 * 再匹配方法
	 */
	MethodMatcher getMethodMatcher();

	Pointcut TRUE = TruePointcut.INSTANCE;
}

事务增强器是BeanFactoryTransactionAttributeSourceAdvisor类,它本身肯定是一个Advisor,所以也会关联一个Pointcut:

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

它关联的是TransactionAttributeSourcePointcut,默认所有Class都通过,只判断方法是否加了@Transaction注解。

/**
 * 目标类的给定方法,是否可以应用事务增强器?
 * 条件:方法事务属性不为空,方法事务属性就是通过解析@Transaction注解获取的
 * @see AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class, boolean)
 */
@Override
public boolean matches(Method method, Class<?> targetClass) {
    if (TransactionalProxy.class.isAssignableFrom(targetClass) ||
            PlatformTransactionManager.class.isAssignableFrom(targetClass) ||
            PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) {
        return false;
    }
    TransactionAttributeSource tas = getTransactionAttributeSource();
    return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

1.1.3 补充:增强的切入点规则判断的时机?

就是判断方法是否具有事务属性TransactionAttribute,即是否加了@Transaction注解。这个切点规则是在哪里触发的呢???Spring AOP判断bean是否需要被增强,是通过AbstractAdvisorAutoProxyCreator#findEligibleAdvisors()查找bean是否有可用的Advisor来判断的。

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    /**
     * 查找容器内所有的Advisor:@Aspect类里定义的各种增强方法
     */
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    /**
     * 根据切点表达式,过滤出可以应用到beanClass的Advisor
     */
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    /**
     * 将ExposeInvocationInterceptor拦截器插入到第一个
     * @see ExposeInvocationInterceptor
     */
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

先获取容器内所有的Advisor,再遍历Advisor和bean是否匹配,这个匹配过程就是通过Advisor.Pointcut切点来判断的,方法是AopUtils#canApply()

1.1.4 ProxyTransactionManagementConfiguration

ProxyTransactionManagementConfiguration是一个配置类,如果算上其继承的父类一共是声明了四个类:
1、TransactionalEventListenerFactory
2、BeanFactoryTransactionAttributeSourceAdvisor
3、TransactionAttributeSource
4、TransactionInterceptor
后三个类相对比较重要,我们一一分析。

@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
 
	/**
	 * 注册BeanFactoryTransactionAttributeSourceAdvisor增强器
	 */
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
		// 注册BeanFactoryTransactionAttributeSourceAdvisor增强器,beanName = "org.springframework.transaction.config.internalTransactionAdvisor"
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource());
		advisor.setAdvice(transactionInterceptor());
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}
 
	/**
	 * 注册TransactionAttributeSource,类型是AnnotationTransactionAttributeSource
	 */
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}
 
	/**
	 * 注册TransactionInterceptor,实现了MethodInterceptor接口,主要用于拦截事务方法的执行
	 */
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor() {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource());
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}
 
}
a、BeanFactoryTransactionAttributeSourceAdvisor

BeanFactoryTransactionAttributeSourceAdvisor:
事务增强器包含Pointcut和Advise。
其中的Pointcut是TransactionAttributeSourcePointcut,主要是一些filter和matches之类的方法,用来匹配被代理类。
而Adivise就是我们之后要介绍的TransactionInterceptor。
Spring AOP基于它给bean创建代理对象,让bean拥有事务增强的能力。本身不具备事务能力,依赖TransactionInterceptor。

b、TransactionAttributeSource

TransactionAttributeSource只是一个接口,扩展了TransactionDefinition,增加了isCandidateClass()的方法(可以用来帮助Pointcut匹配)。
这里使用的具体实现是AnnotationTransactionAttributeSource。因为注解式事务候选类(即要被代理的类)是通过@Transactional注解标识的,并且所有的事务属性也都来自@Transactional注解。

public interface TransactionAttributeSource {
    /**
     * 确定给定的类是否是这个TransactionAttributeSource元数据格式中的事务属性的候选类。
     * * 如果此方法返回false,则不会遍历给定类上的方法,以进行getTransactionAttribute内省。
     * * 因此,返回false是对不受影响的类的优化,而返回true仅仅意味着类需要对给定类上的每个方法进
     * 行完全自省
     * @param targetClass
     * @return
     */

    default boolean isCandidateClass(Class<?> targetClass) {
        return true;
    }

    //返回给定方法的事务属性,如果该方法是非事务性的,则返回null
    @Nullable
    TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass);

}
getTransactionAttribute方法用来获取指定方法上的事务属性信息TransactionAttribute继承了TransactionDefinition接口,TransactionDefinition用来配置事务属性信息的源码如下,而TransactionAttribute中新定义了2个方法,一个方法用来指定事务管理器bean名称的,一个用来判断给定的异常是否需要回滚事务

public interface TransactionAttribute extends TransactionDefinition {

    /**
     * 事务管理器的bean名称
     */
    @Nullable
    String getQualifier();

    /**
     * Return labels associated with this transaction attribute.
     * <p>This may be used for applying specific transactional behavior
     * or follow a purely descriptive nature.
     * @since 5.3
     */
    Collection<String> getLabels();

    /**
    
     * 判断指定的异常是否需要回滚事务
     */
    boolean rollbackOn(Throwable ex);

}

TransactionAttributeSource接口有个实现类AnnotationTransactionAttributeSource负责将@Transaction解析为TransactionAttribute对象, AnnotationTransactionAttributeSource内部最会委托给SpringTransactionAnnotationParser#parseTransactionAnnotation方法来解析@Transaction注解,进而得到事务属性配置信息:RuleBasedTransactionAttribute,代码如下:


    protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
        RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();

        Propagation propagation = attributes.getEnum("propagation");
        rbta.setPropagationBehavior(propagation.value());
        Isolation isolation = attributes.getEnum("isolation");
        rbta.setIsolationLevel(isolation.value());

        rbta.setTimeout(attributes.getNumber("timeout").intValue());
        String timeoutString = attributes.getString("timeoutString");
        Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,
                "Specify 'timeout' or 'timeoutString', not both");
        rbta.setTimeoutString(timeoutString);

        rbta.setReadOnly(attributes.getBoolean("readOnly"));
        rbta.setQualifier(attributes.getString("value"));
        rbta.setLabels(Arrays.asList(attributes.getStringArray("label")));
        //回滚规则
        List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
        for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
            rollbackRules.add(new RollbackRuleAttribute(rbRule));
        }
        for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
            rollbackRules.add(new RollbackRuleAttribute(rbRule));
        }
        for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
            rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
        }
        for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
            rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
        }
        rbta.setRollbackRules(rollbackRules);

        return rbta;
    }
c、TransactionInterceptor

刚才我们说了,TransactionInterceptor就是我们找的Advise。
这个类稍微复杂一点,首先根据事务处理相关的逻辑都放在了其父类TransactionAspectSupport中。此外为了适配动态代理的反射调用(两种代理方式),实现了MethodInterceptor接口。
也就是说,反射发起的入口是MethodInterceptor.invoke(),而反射逻辑在TransactionAspectSupport.invokeWithinTransaction()中。
我们可以简单看invokeWithTransaction()方法中的部分代码:

在这里插入图片描述

1.1.5 总结

@EnableTransactionManagement注解主要导入的类,以及对应的类的作用

在这里插入图片描述

1.1.6 关键的几个类

TransactionDefinition
  1. DefaultTransactionDefinition:TransactionDefinition接口的默认的一个实现,编程式事务中通常使用这个
  2. RuleBasedTransactionAttribute:声明式事务中用到的是这个,这个里面对于事务回滚有一些动态匹配的规则

在这里插入图片描述

事务管理器(PlatformTransactionManager)

负责:获取事务、提交事务、回滚事务,Spring中用PlatformTransactionManager接口表示事务管理器,接口中有三个方法

package org.springframework.transaction;

        import org.springframework.lang.Nullable;

public interface PlatformTransactionManager extends TransactionManager {

    //通过事务管理器获取一个事务,返回TransactionStatus:内部包含事务的状态信息
    TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;

    //根据事务的状态信息提交事务
    void commit(TransactionStatus status) throws TransactionException;

    //根据事务的状态信息回滚事务
    void rollback(TransactionStatus status) throws TransactionException;

}

PlatformTransactionManager有多个实现类,操作db用的是hibernate或者mybatis,那么用到的事务管理器是不一样的,常见的事务管理器实现有下面几个
在这里插入图片描述

二、事务的创建代理对象过程

这个过程和aop的是一样的。
在这里插入图片描述
在这里插入图片描述
获取切面列表
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、事务执行流程

在这里插入图片描述

在这里插入图片描述

3.1 CglibAopProxy#intercept()

在这里插入图片描述

3.2 CglibMethodInvocation#proceed()

在这里插入图片描述

3.3 ReflectiveMethodInvocation#proceed()

在这里插入图片描述

3.4 TransactionInterceptor#invoke()

在这里插入图片描述

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

3.5 TransactionAspectSupport#invokeWithinTransaction()

在这里插入图片描述

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
            final InvocationCallback invocation) throws Throwable {

        //获取我们的事务属源对象
        TransactionAttributeSource tas = getTransactionAttributeSource();
        //通过事务属性源对象获取到我们的事务属性信息
        final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
        //获取我们配置的事务管理器对象
        final PlatformTransactionManager tm = determineTransactionManager(txAttr);
        //从tx属性对象中获取出标注了@Transactionl的方法描述符
        final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

        //处理声明式事务
        if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
            //有没有必要创建事务
            TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

            Object retVal;
            try {
                //调用钩子函数进行回调目标方法
                retVal = invocation.proceedWithInvocation();
            }
            catch (Throwable ex) {
                //抛出异常进行回滚处理
                completeTransactionAfterThrowing(txInfo, ex);
                throw ex;
            }
            finally {
                //清空我们的线程变量中transactionInfo的值
                cleanupTransactionInfo(txInfo);
            }
            //提交事务
            commitTransactionAfterReturning(txInfo);
            return retVal;
        }
        //编程式事务
        else {
          // 这里不是我们的重点,省略...
        }
    }

1、getTransactionAttributeSource()

获取事物属性源对象

/**
	 * Return the transaction attribute source.
	 */
	@Nullable
	public TransactionAttributeSource getTransactionAttributeSource() {
		return this.transactionAttributeSource;
	}

2、getTransactionAttribute()

在这里插入图片描述

	/**
	 * 先进行缓存的获取,如果没有缓存就进行事务属性的获取,如果获取到就放入缓存并返回,否则就返回null
	 */
	@Override
	@Nullable
	public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		// 判断method所在的class是不是Object类型
		if (method.getDeclaringClass() == Object.class) {
			return null;
		}

		// First, see if we have a cached value.
		// 构建缓存key
		Object cacheKey = getCacheKey(method, targetClass);
		// 从缓存中获取
		TransactionAttribute cached = this.attributeCache.get(cacheKey);
		// 有缓存,不会每次computeTransactionAttribute
		if (cached != null) {
			// Value will either be canonical value indicating there is no transaction attribute,
			// or an actual transaction attribute.
			// 判断缓存中的对象是不是空事务属性的对象
			if (cached == NULL_TRANSACTION_ATTRIBUTE) {
				return null;
			}
			else {
				// 存在就直接返回事务属性
				return cached;
			}
		}
		else {
			// We need to work it out.
			// 查找我们的事务注解
			TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
			// Put it in the cache.
			// 若解析出来的事务注解属性为空
			if (txAttr == null) {
				// 往缓存中存放空事务注解属性
				this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
			}
			else {
				// 我们执行方法的描述符:包名+类名+方法名
				String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
				// 把方法描述设置到事务属性上去
				if (txAttr instanceof DefaultTransactionAttribute) {
					((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
				}
				if (logger.isTraceEnabled()) {
					logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
				}
				// 加入缓存
				this.attributeCache.put(cacheKey, txAttr);
			}
			return txAttr;
		}
	}

3、determineTransactionManager(txAttr)

获取配置的事务管理器对象
事务管理器的查找顺序:
1、先看@Transactional中是否通过value或者transactionManager指定了事务管理器
2、TransactionInterceptor.transactionManagerBeanName是否有值,如果有,将通过这个查找事务管理器
3、如果上面2种都没有,将从spring容器中查找TransactionManager类型的事务管理器

在这里插入图片描述

protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
		//事务属性不为空
		if (txAttr == null || this.beanFactory == null) {
			return getTransactionManager();
		}
		//1,查找我们指定的事务管理器名称
		String qualifier = txAttr.getQualifier();
		if (StringUtils.hasText(qualifier)) {
		//如果有就返回
			return determineQualifiedTransactionManager(this.beanFactory, qualifier);
		}
		else if (StringUtils.hasText(this.transactionManagerBeanName)) {
		//2,如果我们没有指定事务名称,就以transactionManagerBeanName名称做查找
			return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
		}
		else {
		//3,如果上述还是没有找,就获取默认的事务管理器
			TransactionManager defaultTransactionManager = getTransactionManager();
			if (defaultTransactionManager == null) {
			//4,如果是空,则在缓存中找,找到就返回
				defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
				if (defaultTransactionManager == null) {
				//5,如果还是没有找到,那就在spring容器中,按类型去查找,然后丢到缓存中去
					defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class);
					this.transactionManagerCache.putIfAbsent(
							DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
				}
			}
			return defaultTransactionManager;
		}
	}

4、asPlatformTransactionManager()

事务管理器转换成PlatformTransactionManager
在这里插入图片描述

private PlatformTransactionManager asPlatformTransactionManager(@Nullable Object transactionManager) {
		if (transactionManager == null || transactionManager instanceof PlatformTransactionManager) {
			return (PlatformTransactionManager) transactionManager;
		}
		else {
			throw new IllegalStateException(
					"Specified transaction manager is not a PlatformTransactionManager: " + transactionManager);
		}
	}

5、createTransactionIfNecessary()

在这里插入图片描述

protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
		// If no name specified, apply method identification as transaction name.
		// 如果没有名称指定则使用方法唯一标识,并使用DelegatingTransactionAttribute封装txAttr
		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) {
				// 获取TransactionStatus事务状态信息
				status = tm.getTransaction(txAttr);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
							"] because no transaction manager has been configured");
				}
			}
		}
		// 根据指定的属性与status准备一个TransactionInfo,
		return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
	}
5.1 AbstractPlatformTransactionManager#getTransaction()
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();

		// 判断当前线程是否存在事务,判断依据为当前线程记录的连接不为空且连接中的transactionActive属性不为空
		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.
		// 如果当前线程不存在事务,但是PropagationBehavior却被声明为PROPAGATION_MANDATORY抛出异常
		if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		// PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW,PROPAGATION_NESTED都需要新建事务
		else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			//没有当前事务的话,REQUIRED,REQUIRES_NEW,NESTED挂起的是空事务,然后创建一个新事务
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
			}
			try {
				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);
		}
	}
1 DataSourceTransactionManager#doGetTransaction()
protected Object doGetTransaction() {
		// 创建一个数据源事务对象
		DataSourceTransactionObject txObject = new DataSourceTransactionObject();
		// 是否允许当前事务设置保持点
		txObject.setSavepointAllowed(isNestedTransactionAllowed());
		/**
		 * TransactionSynchronizationManager 事务同步管理器对象(该类中都是局部线程变量)
		 * 用来保存当前事务的信息,我们第一次从这里去线程变量中获取 事务连接持有器对象 通过数据源为key去获取
		 * 由于第一次进来开始事务 我们的事务同步管理器中没有被存放.所以此时获取出来的conHolder为null
		 */
		ConnectionHolder conHolder =
				(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
		// 非新创建连接则写false
		txObject.setConnectionHolder(conHolder, false);
		// 返回事务对象
		return txObject;
	}
2 AbstractPlatformTransactionManager#suspend()
3 AbstractPlatformTransactionManager#startTransaction()
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
			boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {

		// 是否需要新同步
		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
		// 创建新的事务
		DefaultTransactionStatus status = newTransactionStatus(
				definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
		// 开启事务和连接
		doBegin(transaction, definition);
		// 新同步事务的设置,针对于当前线程的设置
		prepareSynchronization(status, definition);
		return status;
	}
AbstractPlatformTransactionManager
1 newTransactionStatus()
/**
	 * 通过给定的参数创建事务状态,有一个非常关键的参数是newTransaction,用于判断是否是新连接,如果事务不存在,那么肯定是true,如果存在,就需要根据传播特性来决定是否是false了
	 * Create a TransactionStatus instance for the given arguments.
	 */
	protected DefaultTransactionStatus newTransactionStatus(
			TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,
			boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {

		// 是否需要新同步,只要有新同步且当前无同步激活事务
		boolean actualNewSynchronization = newSynchronization &&
				!TransactionSynchronizationManager.isSynchronizationActive();
		return new DefaultTransactionStatus(
				transaction, newTransaction, actualNewSynchronization,
				definition.isReadOnly(), debug, suspendedResources);
	}
2 doBegin()

开启事务的关键方法

protected void doBegin(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");
				}
				// 把我们的数据库连接包装成一个ConnectionHolder对象 然后设置到我们的txObject对象中去
				txObject.setConnectionHolder(new ConnectionHolder(newCon), 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");
				}
				// 关闭自动提交
				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.
			// 绑定我们的数据源和连接到我们的同步管理器上,把数据源作为key,数据库连接作为value 设置到线程变量中
			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);
		}
	}
3 prepareSynchronization()
/**
	 * 设置各种线程私有变量的状态
	 *
	 * Initialize transaction synchronization as appropriate.
	 */
	protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
		if (status.isNewSynchronization()) {
			// 绑定事务激活
			TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
			// 当前事务的隔离级别
			TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
					definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?
							definition.getIsolationLevel() : null);
			// 是否为只读事务
			TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
			// 事务的名称
			TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
			TransactionSynchronizationManager.initSynchronization();
		}
	}
5.2 prepareTransactionInfo()
/**
	 * 创建一个TransactionInfo,然后把事务管理器,事务注解属性,方法标识符,事务状态设置进入,然后绑定到当前线程私有变量里
	 */
	protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, String joinpointIdentification,
			@Nullable TransactionStatus status) {

		// 创建事务信息
		TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
		if (txAttr != null) {
			// We need a transaction for this method...
			if (logger.isTraceEnabled()) {
				logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
			}
			// 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.");
			}
		}

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

6、调用proceedWithInvocation()执行业务逻辑

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7、completeTransactionAfterThrowing()异常会进入当前方法

/**
	 * 如果支持回滚的话就进行回滚,否则就处理提交,提交里面如果TransactionStatus.isRollbackOnly()=true的话也会进行回滚处理
	 */
	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;
				}
			}
		}
	}
7.1 rollbackOn() 判断当前事务是否需要回滚
@Override
public boolean rollbackOn(Throwable ex) {
    RollbackRuleAttribute winner = null;
    int deepest = Integer.MAX_VALUE;
    //@Transactional中可以通过rollbackFor指定需要回滚的异常列表,通过noRollbackFor属性指定不 需要回滚的异常
    //根据@Transactional中指定的回滚规则判断ex类型的异常是否需要回滚
    if (this.rollbackRules != null) {
        for (RollbackRuleAttribute rule : this.rollbackRules) {
        // 如果抛出的异常类型,和事务定义的异常类型匹配,证明该异常需要捕获。
// 之所以用递归,不仅需要判断抛出异常的本身,还需要判断它继承的父类异常,满足任意一个即可捕获。
            int depth = rule.getDepth(ex);
            if (depth >= 0 && depth < deepest) {
                deepest = depth;
                winner = rule;
            }
        }
    }

    // 若@Transactional注解中没有匹配到,这走默认的规则,将通过super.rollbackOn来判断
    if (winner == null) {
        return super.rollbackOn(ex);
    }

    return !(winner instanceof NoRollbackRuleAttribute);
}

super.rollbackOn(ex)源码如下,可以看出默认情况下,异常类型是RuntimeException或者Error的情况下,事务才会回滚。

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

8、cleanupTransactionInfo()

/**
	 * 清除事务信息
	 *
	 * Reset the TransactionInfo ThreadLocal.
	 * <p>Call this in all cases: exception or normal return!
	 * @param txInfo information about the current transaction (may be {@code null})
	 */
	protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
		if (txInfo != null) {
			txInfo.restoreThreadLocalStatus();
		}
	}

9、commitTransactionAfterReturning()

/**
	 * 调用事务管理器的提交方法
	 *
	 * Execute after successful completion of call, but not after an exception was handled.
	 * Do nothing if we didn't create a transaction.
	 * @param txInfo information about the current transaction
	 */
	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、创建事务流程图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1069573.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI:11-基于深度学习的鱼类识别

当今,人工智能和深度学习已经成为许多领域的关键技术。在生态学和环境保护领域,鱼类识别是一项重要的任务,因为准确识别和监测鱼类种群对于保护水生生物多样性和可持续渔业管理至关重要。基于深度学习的鱼类识别系统能够自动识别和分类不同种类的鱼类,为生态学研究和渔业管…

ChatGPT Vision初体验

本周&#xff0c;OpenAI为其广受欢迎的 ChatGPT 平台发布了一项突破性的补充。除了处理文本之外&#xff0c;ChatGPT 现在还可以处理图像并聊天。 很难夸大这件事的重要性。目前多达70% 的内容是视觉内容而不是书面内容。人们每年会生成数千张照片&#xff0c;而当今许多最大的…

设计模式 - 结构型模式考点篇:代理模式(静态代理、JDK 动态代理、CGLIB 动态代理)

目录 一、代理模式 一句话概括 1.1、代理模式概述 1.2、静态代理 1.3、JDK 动态代理 1.4、CGLIB 动态代理 1.5、对比三种代理 1.5.1、jdk 代理 VS CGLIB 代理 1.5.2、动态代理 VS 静态代理 1.6、优缺点 1.7、使用场景 一、代理模式 一句话概括 教你将类和对象结合再…

Mac mov转mp4,详细转换步骤

Mac mov转mp4怎么转&#xff1f;视频文件格式为.mov是由Apple公司所开发的特殊格式。因其只能在苹果设备上播放&#xff0c;与他人分享时就会变得困难。为此&#xff0c;我们通常会选择使用MP4这种最受欢迎的视频格式。在日常使用中&#xff0c;MP4成为了大家首选的视频格式。而…

【Docker】 docker中apt-get update过慢,这样配置瞬间提速!

docker中apt-get update过慢&#xff0c;这样配置瞬间提速&#xff01; 源官网全球镜像站 源 今天办公地点的网络出奇的差&#xff0c;看电影看小说打游戏完全没影响&#xff0c;只要更新就蜗速前进&#xff0c;只能从网上翻下&#xff0c;看看有没有网速快的下载源。 碰巧看到…

模范思路,单基因泛癌+实验轻松拿捏sci8+。

今天给同学们分享一篇单基因泛癌单细胞实验的生信文章“Pan-cancer analysis of Krppel-like factor 3 and its carcinogenesis in pancreatic cancer”&#xff0c;这篇文章于2023年8月3日发表在Front Immunol期刊上&#xff0c;影响因子为8.786。 Krppel-like factor 3&#…

vue.js处理数组对象中某个字段是否变为两个字段

一、场景&#xff1a; 产品要求做一个时间步骤条&#xff0c;使用目前后端已返回的数据进行操作实现。时间步骤条要求日期和时间分开显示且相同日期只显示第一个日期。 图左边为实现效果&#xff0c;右边为后台返回的接口。接口中current字段表示当前到达第几步&#xff0c;从…

2023年软件测试工具总结 —— 接口测试工具

接口测试的全称是应用程序编程接口&#xff08;API&#xff09;测试&#xff0c;从原理上来说&#xff0c;接口测试是模拟客户端向服务器端发送请求&#xff0c;然后检查能否获得正确的返回信息。接口测试用于测试RESTful API、SOAP Web服务&#xff0c;这些服务可以通过HTTP、…

Java基础知识总结(2023版)

目录 一、Java基础1、Java 基础2、Java 进阶3、Java8新特性4、Java集合5、Java高并发6、Java代码实例 二、MySQL数据库三、Spring Boot框架&#xff08;35天&#xff09;四、Redis中间件五、MongoDB数据库六、Netty网络编程七、23种设计模式八、微服务九、JavaScript零基础入门…

Aurora中的策略模式和模板模式

Aurora中的策略模式和模板模式 在aurora中为了方便以后的扩展使用了策略模式和模板模式实现图片上传和搜索功能&#xff0c;能够在配置类中设置使用Oss或者minio上传图片&#xff0c;es或者mysql文章搜索。后续有新的上传方式或者搜索方式只需要编写对应的实现类即可&#xff…

批量对比文件夹下文件

软件 产品 | Beyond Compare 中文官方网站 软解破解 Beyond Compare 4密钥过期&#xff0c;解决办法&#xff0c;超实用 批量文件对比 最后显示红色的文件&#xff0c;即为文件两者内容不同的

面了10家却收不到1个offer,自我介绍你踩雷了吗?

每一次离职&#xff0c;都是为了重新开始&#xff1b;每一次寻找新的工作&#xff0c;都面临着巨大的竞争。找工作就像找对象&#xff0c;除了需要一定的缘分外&#xff0c;也需要掌握一定的技巧。 有的人爱恋TA的人排到长城&#xff0c;有的人却一直母胎单身&#xff1b;有的人…

Spring源码解析(十一):spring事务配置类源码

Spring源码系列文章 Spring源码解析(一)&#xff1a;环境搭建 Spring源码解析(二)&#xff1a;bean容器的创建、默认后置处理器、扫描包路径bean Spring源码解析(三)&#xff1a;bean容器的刷新 Spring源码解析(四)&#xff1a;单例bean的创建流程 Spring源码解析(五)&…

vue3使用echarts实现地图撒点、飞线等功能

echarts地图配置参考链接 链接2 vue3使用echarts map.vue <template><div class"echart-demo" id"demo"></div> </template><script setup lang"ts"> //引入echart和json数据 import * as echarts from echarts…

ffmpeg ts 关于av_seek_frame

1 ffmpeg命令行 一般对视频文件的裁剪 我们通过一行 ffmpeg命令行即可实现&#xff0c;比如 ffmpeg -ss 0.5 - t 3 - i a.mp4 vcodec copy b.mp4 其中 -ss 放置较前 开启精准seek定位 对于mp4而言 seek将从moov中相关索引表查找 0.5s时刻附近最近的关键帧 &#xff08;此描述…

systemd服务日志重定向到文件

方式一&#xff08;centos7&#xff09; [Service] ExecStart"/usr/bin/sh test.sh >> info.log 2>&1"方式二&#xff08;centos8&#xff09; StandardOutput 和 StandardError&#xff0c;用于重定向标准输出和标准错误输出 [Service] StandardOut…

k8s containerd查看镜像

直接查看crictl image会报错&#xff1a; 1) crictl config runtime-endpoint unix:///run/containerd/containerd.sock 2) vi /etc/crictl.yaml 3) systemctl daemon-reload 此时&#xff0c;再查看image:

Kettle连接数据库[MySQL]报错

在连接数据库页面填写完成后点击“测试” 报错信息&#xff1a; 错误连接数据库 [ETLqiangzi] : org.pentaho.di.core.exception.KettleDatabaseException: Error occurred while trying to connect to the databaseDriver class org.gjt.mm.mysql.Driver could not be found…

nssm nginx window 部署和开机启动服务

部署 去到Nginx官网&#xff1a;nginx news &#xff0c;然后点击“download” 在nginx的配置文件是conf目录下的nginx.conf nginx.exe http://localhost 在cmd命令窗口里面输入nginx命令(快速停止nginx) &#xff1a; nginx -s stop 或者使用(完整有序的停止nginx)命…

elasticsearch深度分页问题

一、深度分页方式from size es 默认采用的分页方式是 from size 的形式&#xff0c;在深度分页的情况下&#xff0c;这种使用方式效率是非常低的&#xff0c;比如我们执行如下查询 1 GET /student/student/_search 2 { 3 "query":{ 4 "match_all":…