欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中SpringBoot的@Transactional原理

 更新時(shí)間:2023年07月11日 11:30:36   作者:賢子磊  
這篇文章主要介紹了Java中SpringBoot的@Transactional原理,面向元數(shù)據(jù)遍歷已經(jīng)成為越來越多開發(fā)者的偏好,因此原理從Springboot的EnableTransactionManagement注解說起,需要的朋友可以參考下

一、@Transactional的使用

  • 加在方法上:方法內(nèi)的所有操作處于一個(gè)事務(wù)中
  • 加在類上
    • 該類的所有public修飾的方法都具有共享事務(wù)屬性
    • 如果方法和類上都有事務(wù)注解,方法上的事務(wù)注解優(yōu)先

二、@Transactional原理

Springboot目前最為流行,它的約定大于配置的特性深受大家喜歡,注解驅(qū)動(dòng)開發(fā)已成為主流。面向元數(shù)據(jù)遍歷已經(jīng)成為越來越多開發(fā)者的偏好,因此原理從Springboot的EnableTransactionManagement注解說起

1、@EnableTransactionManagement

表示開啟事務(wù)管理

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
	boolean proxyTargetClass() default false;
	AdviceMode mode() default AdviceMode.PROXY;
	int order() default Ordered.LOWEST_PRECEDENCE;
}

通過Import導(dǎo)入了TransactionManagementConfigurationSelector類,其中默認(rèn)的AdviceMode為AdviceMode.PROXY,即默認(rèn)使用JDK的動(dòng)態(tài)代理生成代理類。

2、TransactionManagementConfigurationSelector

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
	/**
	 * 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) {
            //根據(jù)上面注解的默認(rèn)配置,adviceMode默認(rèn)為PROXY
			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);
	}
}

TransactionManagementConfigurationSelector繼承自AdviceModeImportSelector類,實(shí)現(xiàn)selectImports方法可以注入對(duì)應(yīng)的bean,根據(jù)EnableTransactionManagement注解的默認(rèn)配置,adviceMode默認(rèn)為PROXY。所以這里會(huì)注入AutoProxyRegistrar和ProxyTransactionManagementConfiguration這兩個(gè)類

  • AutoProxyRegistrar
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.
	 * <p>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;
        // 這里面需要特別注意的是:這里是拿到所有的注解類型~~~而不是只拿@EnableAspectJAutoProxy這個(gè)類型的
		// 原因:因?yàn)閙ode、proxyTargetClass等屬性會(huì)直接影響到代理得方式,而擁有這些屬性的注解至少有:
		// @EnableTransactionManagement、@EnableAsync、@EnableCaching等~~~~
		// 甚至還有啟用AOP的注解:@EnableAspectJAutoProxy它也能設(shè)置`proxyTargetClass`這個(gè)屬性的值,因此也會(huì)產(chǎn)生關(guān)聯(lián)影響~
		Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
		for (String annType : annTypes) {
			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
			if (candidate == null) {
				continue;
			}
            //獲取mode和proxyTargetClass的屬性
			Object mode = candidate.get("mode");
			Object proxyTargetClass = candidate.get("proxyTargetClass");
            //如果存在這兩個(gè)屬性且類型符合要求
			if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
					Boolean.class == proxyTargetClass.getClass()) {
				candidateFound = true;
				if (mode == AdviceMode.PROXY) {
                    //向容器注入的是一個(gè)InfrastructureAdvisorAutoProxyCreator,它主要是讀取Advisor類,并對(duì)符合的bean進(jìn)行二次代理
                    //如果出現(xiàn)多次的話,這里不是覆蓋的形式,而是以第一次的為主
					//當(dāng)然它內(nèi)部有做等級(jí)的提升之類的
					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                    //看要不要強(qiáng)制使用CGLIB的方式(這個(gè)屬性若出現(xiàn)多次,是會(huì)是覆蓋的形式)
					if ((Boolean) proxyTargetClass) {
						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
						return;
					}
				}
			}
		}
        //如果一個(gè)都沒有找到則打印info日志
		//可能是自己注入這個(gè)類,而不是使用注解去注入
		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));
		}
	}
}

主要作用就是往Spring容器注入了一個(gè)自動(dòng)代理創(chuàng)建器:org.springframework.aop.config.internalAutoProxyCreator,并且看看是采用CGLIB還是JDK代理

  • ProxyTransactionManagementConfiguration
@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
			TransactionAttributeSource transactionAttributeSource,
			TransactionInterceptor transactionInterceptor) {
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource);
		advisor.setAdvice(transactionInterceptor);
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor(
			TransactionAttributeSource transactionAttributeSource) {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource);
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}
}

這里是往容器中注入事務(wù)相關(guān)的bean

  • BeanFactoryTransactionAttributeSourceAdvisor:事務(wù)的核心,下面分析
  • TransactionAttributeSource:事務(wù)屬性源
  • TransactionInterceptor:事務(wù)攔截器,它是個(gè)MethodInterceptor。(我們可以自定義個(gè)beanName一模一樣的TransactionInterceptor來覆蓋默認(rèn)的事務(wù)攔截器)

(我們可以自定義個(gè)beanName一模一樣的TransactionInterceptor來覆蓋默認(rèn)的事務(wù)攔截器)

再看父類AbstractTransactionManagementConfiguration

@Configuration
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {
	@Nullable
	protected AnnotationAttributes enableTx;
	/**
	 * Default transaction manager, as configured through a {@link TransactionManagementConfigurer}.
	 */
	@Nullable
	protected TransactionManager txManager;
	@Override
	public void setImportMetadata(AnnotationMetadata importMetadata) {
		this.enableTx = AnnotationAttributes.fromMap(
				importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
		if (this.enableTx == null) {
			throw new IllegalArgumentException(
					"@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName());
		}
	}
    //這里可以通過配置文件注入一個(gè)默認(rèn)的事務(wù)管理器
	@Autowired(required = false)
	void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
		if (CollectionUtils.isEmpty(configurers)) {
			return;
		}
        //最多只允許配置一個(gè)
		if (configurers.size() > 1) {
			throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
		}
		TransactionManagementConfigurer configurer = configurers.iterator().next();
		this.txManager = configurer.annotationDrivenTransactionManager();
	}
    //注冊(cè)一個(gè)監(jiān)聽器工廠,用以支持@TransactionalEventListener注解標(biāo)注的方法,來監(jiān)聽事務(wù)相關(guān)的事件
	@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
		return new TransactionalEventListenerFactory();
	}
}
  • BeanFactoryTransactionAttributeSourceAdvisor
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
	@Nullable
	private TransactionAttributeSource transactionAttributeSource;
    //切面:決定了哪些類會(huì)被切入,從而生成的代理對(duì)象
	private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		@Override
		@Nullable
		protected TransactionAttributeSource getTransactionAttributeSource() {
			return transactionAttributeSource;
		}
	};
	// 可議手動(dòng)設(shè)置一個(gè)事務(wù)屬性源
	public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
		this.transactionAttributeSource = transactionAttributeSource;
	}
	//可以指定ClassFilter  默認(rèn)情況下:ClassFilter classFilter = ClassFilter.TRUE;  匹配所有的類的
	public void setClassFilter(ClassFilter classFilter) {
		this.pointcut.setClassFilter(classFilter);
	}
    //此處pointcut就是使用自己的這個(gè)pointcut去切入
	@Override
	public Pointcut getPointcut() {
		return this.pointcut;
	}
}

我們繼續(xù)查看TransactionAttributeSourcePointcut類

abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
	protected TransactionAttributeSourcePointcut() {
		setClassFilter(new TransactionAttributeSourceClassFilter());
	}
	@Override
	public boolean matches(Method method, Class<?> targetClass) {
		TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}
	@Override
	public boolean equals(@Nullable Object other) {
		if (this == other) {
			return true;
		}
		if (!(other instanceof TransactionAttributeSourcePointcut)) {
			return false;
		}
		TransactionAttributeSourcePointcut otherPc = (TransactionAttributeSourcePointcut) other;
		return ObjectUtils.nullSafeEquals(getTransactionAttributeSource(), otherPc.getTransactionAttributeSource());
	}
	@Override
	public int hashCode() {
		return TransactionAttributeSourcePointcut.class.hashCode();
	}
	@Override
	public String toString() {
		return getClass().getName() + ": " + getTransactionAttributeSource();
	}
	//由子類提供事務(wù)屬性源
	@Nullable
	protected abstract TransactionAttributeSource getTransactionAttributeSource();
	/**
	 * {@link ClassFilter} that delegates to {@link TransactionAttributeSource#isCandidateClass}
	 * for filtering classes whose methods are not worth searching to begin with.
	 */
	private class TransactionAttributeSourceClassFilter implements ClassFilter {
		@Override
		public boolean matches(Class<?> clazz) {
            // 實(shí)現(xiàn)了如下三個(gè)接口的子類,就不需要被代理了  直接放行
		// TransactionalProxy它是SpringProxy的子類。如果是被TransactionProxyFactoryBean生產(chǎn)出來的Bean,就會(huì)自動(dòng)實(shí)現(xiàn)此接口,那么就不會(huì)被這里再次代理了
		// PlatformTransactionManager:spring抽象的事務(wù)管理器
		// PersistenceExceptionTranslator對(duì)RuntimeException轉(zhuǎn)換成DataAccessException的轉(zhuǎn)換接口
			if (TransactionalProxy.class.isAssignableFrom(clazz) ||
					PlatformTransactionManager.class.isAssignableFrom(clazz) ||
					PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
				return false;
			}
            // 重要:拿到事務(wù)屬性源~~~~~~
			// 如果tas == null表示沒有配置事務(wù)屬性源,那是全部匹配的,也就是說所有的方法都匹配
			// 或者 標(biāo)注了@Transaction這樣的注解的方法才會(huì)給與匹配
			TransactionAttributeSource tas = getTransactionAttributeSource();
			return (tas == null || tas.isCandidateClass(clazz));
		}
	}
}

關(guān)于matches方法的調(diào)用時(shí)機(jī):只要是容器內(nèi)的每個(gè)Bean,都會(huì)經(jīng)過AbstractAutoProxyCreator#postProcessAfterInitialization從而會(huì)調(diào)用wrapIfNecessary方法,因此容器內(nèi)所有的Bean的所有方法在容器啟動(dòng)時(shí)候都會(huì)執(zhí)行此matche方法。

3、TransactionInterceptor

事務(wù)處理的核心邏輯就在這個(gè)攔截器里面,我們先看下Spring事務(wù)的三個(gè)接口

  • TransactionStatus:代表一個(gè)事務(wù)的具體運(yùn)行狀態(tài)、以及還原點(diǎn)
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
	//判斷該事務(wù)里面是否含有還原點(diǎn)
	boolean hasSavepoint();
	//將基礎(chǔ)會(huì)話刷新到數(shù)據(jù)存儲(chǔ)
	@Override
	void flush();
}
public interface TransactionExecution {
	//判斷當(dāng)前的事務(wù)是否是新事務(wù)
	boolean isNewTransaction();
	//設(shè)置這個(gè)目的是為了讓事務(wù)的唯一結(jié)果是進(jìn)行回滾。
    //因此如果你在外層給try catche住不讓事務(wù)回滾,就會(huì)拋出你可能常見的異常:
	//Transaction rolled back because it has been marked as rollback-only
	void setRollbackOnly();
	//判斷事務(wù)的是不是必須回滾
	boolean isRollbackOnly();
	//判斷事務(wù)是否結(jié)果(不管是commit還是rollback)
	boolean isCompleted();
}
  • TransactionDefinition:用于描述隔離級(jí)別、超時(shí)時(shí)間、是否為只讀事務(wù)和事務(wù)傳播規(guī)則
  • PlatformTransactionManager:事務(wù)管理器,包含commit、rollbackgetTransaction三個(gè)方法

根據(jù)上面的分析,我們知道TransactionInterceptor本質(zhì)就是一個(gè)MethodInterceptor,被事務(wù)攔截的方法最終都會(huì)執(zhí)行到此增強(qiáng)器身上。 MethodInterceptor是個(gè)環(huán)繞通知,敲好符合我們的開啟、提交、回滾事務(wù)等操作。

3.1、invoke方法

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
	/**
	 * Create a new TransactionInterceptor.
	 * <p>Transaction manager and transaction attributes still need to be set.
	 * @see #setTransactionManager
	 * @see #setTransactionAttributes(java.util.Properties)
	 * @see #setTransactionAttributeSource(TransactionAttributeSource)
	 */
	public TransactionInterceptor() {
	}
	/**
	 * Create a new TransactionInterceptor.
	 * @param ptm the default transaction manager to perform the actual transaction management
	 * @param attributes the transaction attributes in properties format
	 * @see #setTransactionManager
	 * @see #setTransactionAttributes(java.util.Properties)
	 */
	public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
		setTransactionManager(ptm);
		setTransactionAttributes(attributes);
	}
	/**
	 * Create a new TransactionInterceptor.
	 * @param ptm the default transaction manager to perform the actual transaction management
	 * @param tas the attribute source to be used to find transaction attributes
	 * @see #setTransactionManager
	 * @see #setTransactionAttributeSource(TransactionAttributeSource)
	 */
	public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
		setTransactionManager(ptm);
		setTransactionAttributeSource(tas);
	}
	@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);
	}
	//---------------------------------------------------------------------
	// Serialization support
	//---------------------------------------------------------------------
	private void writeObject(ObjectOutputStream oos) throws IOException {
		// Rely on default serialization, although this class itself doesn't carry state anyway...
		oos.defaultWriteObject();
		// Deserialize superclass fields.
		oos.writeObject(getTransactionManagerBeanName());
		oos.writeObject(getTransactionManager());
		oos.writeObject(getTransactionAttributeSource());
		oos.writeObject(getBeanFactory());
	}
	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
		// Rely on default serialization, although this class itself doesn't carry state anyway...
		ois.defaultReadObject();
		// Serialize all relevant superclass fields.
		// Superclass can't implement Serializable because it also serves as base class
		// for AspectJ aspects (which are not allowed to implement Serializable)!
		setTransactionManagerBeanName((String) ois.readObject());
		setTransactionManager((PlatformTransactionManager) ois.readObject());
		setTransactionAttributeSource((TransactionAttributeSource) ois.readObject());
		setBeanFactory((BeanFactory) ois.readObject());
	}
}

其中invoke調(diào)用父類TransactionAspectSupport的invokeWithinTransaction方法

3.2、invokeWithinTransaction方法

public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
	/**
	 * 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.
	 * @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 (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);
			}
		}
		//獲取事務(wù)屬性源
		TransactionAttributeSource tas = getTransactionAttributeSource();
        //獲取方法對(duì)應(yīng)的事務(wù)屬性
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
        //找到合適事務(wù)管理器
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
        //獲取方法的唯一標(biāo)識(shí)
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
        // 如果txAttr為空或者tm屬于非CallbackPreferringPlatformTransactionManager,執(zhí)行目標(biāo)增強(qiáng)
		// 在TransactionManager上,CallbackPreferringPlatformTransactionManager實(shí)現(xiàn)PlatformTransactionManager接口,暴露出一個(gè)方法用于執(zhí)行事務(wù)處理中的回調(diào)
		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
			//看是否有必要?jiǎng)?chuàng)建一個(gè)事務(wù),根據(jù)事務(wù)傳播行為做出相應(yīng)的判斷
			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
			Object retVal;
			try {
				//回調(diào)方法執(zhí)行,執(zhí)行目標(biāo)方法(原有的業(yè)務(wù)邏輯)
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				// 出現(xiàn)異常了,進(jìn)行回滾(注意:并不是所有異常都會(huì)rollback的)
                //如果出現(xiàn)的異常不需要rollback,則會(huì)進(jìn)行commit
				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);
				}
			}
			// 目標(biāo)方法完全執(zhí)行完成后,提交事務(wù)
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}
		//編程式事務(wù)處理(CallbackPreferringPlatformTransactionManager) 會(huì)走這里 
		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;
			}
		}
	}
}

邏輯很清晰,本質(zhì)就是通過try…catch…進(jìn)行事務(wù)的提交或者回滾。我們看下里面的獲取事務(wù)管理器的方法determineTransactionManager

3.3、determineTransactionManager方法

@Nullable
protected PlatformTransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
    //如果這兩個(gè)都沒配置,所以肯定是手動(dòng)設(shè)置了PlatformTransactionManager的,那就直接返回即可
    if (txAttr == null || this.beanFactory == null) {
        return asPlatformTransactionManager(getTransactionManager());
    }
    //qualifier相當(dāng)于beanName
    String qualifier = txAttr.getQualifier();
    if (StringUtils.hasText(qualifier)) {
        //根據(jù)此名稱以及PlatformTransactionManager.class 去容器內(nèi)找bean
        return determineQualifiedTransactionManager(this.beanFactory, qualifier);
    }
    // 若沒有指定qualifier,那再看看是否指定了transactionManagerBeanName
    else if (StringUtils.hasText(this.transactionManagerBeanName)) {
        return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
    }
    //如果都沒指定,那就不管了。直接根據(jù)類型去容器里找 getBean(Class)
    //注:如果容器里面有多個(gè)PlatformTransactionManager,那么就會(huì)導(dǎo)致報(bào)錯(cuò)
    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;
    }
}

3.4、createTransactionIfNecessary

再看下創(chuàng)建事務(wù)的方法createTransactionIfNecessary,在看方法前,我們先看下返回的TransactionInfo類

protected static final class TransactionInfo {
    // 當(dāng)前事務(wù)的事務(wù)管理器
    @Nullable
    private final PlatformTransactionManager transactionManager;
    // 當(dāng)前事務(wù)的事務(wù)屬性
    @Nullable
    private final TransactionAttribute transactionAttribute;
    //joinpoint標(biāo)識(shí)
    private final String joinpointIdentification;
    // 當(dāng)前事務(wù)的TransactionStatus
    @Nullable
    private TransactionStatus transactionStatus;
    //保存當(dāng)前事務(wù)所在的父事務(wù)上下文的引用,構(gòu)成了一個(gè)鏈,準(zhǔn)確的說是一個(gè)有向無環(huán)圖
    @Nullable
    private TransactionInfo oldTransactionInfo;
    public TransactionInfo(@Nullable PlatformTransactionManager transactionManager,
                           @Nullable TransactionAttribute transactionAttribute, String joinpointIdentification) {
        this.transactionManager = transactionManager;
        this.transactionAttribute = transactionAttribute;
        this.joinpointIdentification = joinpointIdentification;
    }
    public PlatformTransactionManager getTransactionManager() {
        Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
        return this.transactionManager;
    }
    @Nullable
    public TransactionAttribute getTransactionAttribute() {
        return this.transactionAttribute;
    }
    /**
		 * Return a String representation of this joinpoint (usually a Method call)
		 * for use in logging.
		 */
    public String getJoinpointIdentification() {
        return this.joinpointIdentification;
    }
    //創(chuàng)建一個(gè)新的事務(wù)
    public void newTransactionStatus(@Nullable TransactionStatus status) {
        this.transactionStatus = status;
    }
    @Nullable
    public TransactionStatus getTransactionStatus() {
        return this.transactionStatus;
    }
    /**
		 * Return whether a transaction was created by this aspect,
		 * or whether we just have a placeholder to keep ThreadLocal stack integrity.
		 */
    public boolean hasTransaction() {
        return (this.transactionStatus != null);
    }
    //綁定當(dāng)前正在處理的事務(wù)的所有信息到ThreadLocal
    private void bindToThread() {
        // Expose current TransactionStatus, preserving any existing TransactionStatus
        // for restoration after this transaction is complete.
        //先從線程中拿出來老的,再把新的(也就是當(dāng)前)綁定進(jìn)去
        this.oldTransactionInfo = transactionInfoHolder.get();
        transactionInfoHolder.set(this);
    }
    //當(dāng)前事務(wù)處理完之后,恢復(fù)父事務(wù)上下文
    private void restoreThreadLocalStatus() {
        // Use stack to restore old transaction TransactionInfo.
        // Will be null if none was set.
        transactionInfoHolder.set(this.oldTransactionInfo);
    }
    @Override
    public String toString() {
        return (this.transactionAttribute != null ? this.transactionAttribute.toString() : "No transaction");
    }
}

然后再看創(chuàng)建事務(wù)的方法createTransactionIfNecessary

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;
            }
        };
    }
	//從事務(wù)管理器里,通過txAttr拿出來一個(gè)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");
            }
        }
    }
    //通過TransactionStatus 等,轉(zhuǎn)換成一個(gè)通用的TransactionInfo
    return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

再看方法prepareTransactionInfo

protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
                                                 @Nullable TransactionAttribute txAttr, String joinpointIdentification,
                                                 @Nullable TransactionStatus status) {
	//構(gòu)造一個(gè)TransactionInfo
    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.
    //把生成的TransactionInfo并綁定到當(dāng)前線程的ThreadLocal
    txInfo.bindToThread();
    return txInfo;
}

3.5、commitTransactionAfterReturning

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        if (logger.isTraceEnabled()) {
            logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
        }
        //直接使用事務(wù)管理器提交事務(wù)
        txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
    }
}

3.6、completeTransactionAfterThrowing

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);
        }
        //如果有事務(wù)屬性了,那就調(diào)用rollbackOn看看這個(gè)異常需不需要回滾
        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;
            }
        }
    }
}

3.7、cleanupTransactionInfo

protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
    if (txInfo != null) {
        //清除(解綁)事務(wù)
        txInfo.restoreThreadLocalStatus();
    }
}

4、PlatformTransactionManager

事務(wù)管理器接口

public interface PlatformTransactionManager extends TransactionManager {
	//創(chuàng)建事務(wù)
	TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException;
	//提交事務(wù)
	void commit(TransactionStatus status) throws TransactionException;
	//回滾事務(wù)
	void rollback(TransactionStatus status) throws TransactionException;
}

4.1、AbstractPlatformTransactionManager

是對(duì)PlatformTransactionManager的一個(gè)抽象實(shí)現(xiàn),這個(gè)基類提供了以下工作流程處理

  • 確定如果有現(xiàn)有的事務(wù);
  • 應(yīng)用適當(dāng)?shù)膫鞑バ袨?
  • 如果有必要暫停和恢復(fù)事務(wù);
  • 提交時(shí)檢查rollback-only標(biāo)記;
  • 應(yīng)用適當(dāng)?shù)男薷漠?dāng)回滾(實(shí)際回滾或設(shè)置rollback-only);
  • 觸發(fā)同步回調(diào)注冊(cè)(如果事務(wù)同步是激活的)

(1)getTransaction方法

@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
    throws TransactionException {
    //如果沒有配置事務(wù)屬性,則使用默認(rèn)的事務(wù)屬性
    TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
    //獲取事務(wù),具體的實(shí)現(xiàn)由具體的事務(wù)處理器提供
    Object transaction = doGetTransaction();
    boolean debugEnabled = logger.isDebugEnabled();
    //檢查當(dāng)前線程是否存在事務(wù),如果是則直接處理已存在的事務(wù),isExistingTransaction方法由子類去實(shí)現(xiàn)
    if (isExistingTransaction(transaction)) {
        // Existing transaction found -> check propagation behavior to find out how to behave.
        return handleExistingTransaction(def, transaction, debugEnabled);
    }
    //超時(shí)時(shí)間的校驗(yàn)
    if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
        throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
    }
    //處理事務(wù)屬性中配置的事務(wù)傳播特性
    // PROPAGATION_MANDATORY 如果已經(jīng)存在一個(gè)事務(wù),支持當(dāng)前事務(wù)。如果沒有一個(gè)活動(dòng)的事務(wù),則拋出異常
    if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
        throw new IllegalTransactionStateException(
            "No existing transaction found for transaction marked with propagation 'mandatory'");
    }
    //如果事務(wù)傳播特性為required、required_new或nested
    else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
             def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
             def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
        // 掛起,doSuspend()由子類去實(shí)現(xiàn)
        // 掛起操作,觸發(fā)相關(guān)的掛起注冊(cè)的事件,把當(dāng)前線程事物的所有屬性都封裝好,放到一個(gè)SuspendedResourcesHolder
        // 然后清空清空一下當(dāng)前線程事務(wù)
        SuspendedResourcesHolder suspendedResources = suspend(null);
        if (debugEnabled) {
            logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
        }
        //此處,開始創(chuàng)建事務(wù)
        try {
            boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
            //創(chuàng)建一個(gè)新的事務(wù)狀態(tài)  就是new DefaultTransactionStatus()  把個(gè)屬性都賦值上
            DefaultTransactionStatus status = newTransactionStatus(
                def, transaction, true, newSynchronization, debugEnabled, suspendedResources);
            //開始事務(wù),抽象方法,由子類去實(shí)現(xiàn)~
            doBegin(transaction, def);
            //初始化和同步事務(wù)狀態(tài)
            prepareSynchronization(status, def);
            return status;
        }
        catch (RuntimeException | Error ex) {
            //重新開始 doResume由子類去實(shí)現(xiàn)
            resume(null, suspendedResources);
            throw ex;
        }
    }
    // 走到這里表示傳播屬性就是不需要事務(wù)的,直接創(chuàng)建一個(gè)
    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);
    }
}

(2)commit方法

@Override
public final void commit(TransactionStatus status) throws TransactionException {
    //如果是一個(gè)已經(jīng)完成的事物,不可重復(fù)提交
    if (status.isCompleted()) {
        throw new IllegalTransactionStateException(
            "Transaction is already completed - do not call commit or rollback more than once per transaction");
    }
    DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
    // 如果已經(jīng)標(biāo)記為了需要回滾,那就執(zhí)行回滾吧
    if (defStatus.isLocalRollbackOnly()) {
        if (defStatus.isDebug()) {
            logger.debug("Transactional code has requested rollback");
        }
        processRollback(defStatus, false);
        return;
    }
	//  shouldCommitOnGlobalRollbackOnly這個(gè)默認(rèn)值是false,目前只有JTA事務(wù)復(fù)寫成true了
	// isGlobalRollbackOnly:是否標(biāo)記為了全局的RollbackOnly
    if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
        if (defStatus.isDebug()) {
            logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
        }
        processRollback(defStatus, true);
        return;
    }
	// 提交事務(wù),會(huì)考慮到還原點(diǎn)、新事務(wù)、事務(wù)是否是rollback-only之類的
    processCommit(defStatus);
}

(3)rollback方法

@Override
public final void rollback(TransactionStatus status) throws TransactionException {
    if (status.isCompleted()) {
        throw new IllegalTransactionStateException(
            "Transaction is already completed - do not call commit or rollback more than once per transaction");
    }
    DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
    //交給子類去實(shí)現(xiàn)
    processRollback(defStatus, false);
}

4.2、DataSourceTransactionManager

以最為常用DataSourceTransactionManager作為實(shí)現(xiàn)類看看內(nèi)部具體如何實(shí)現(xiàn)

(1)doGetTransaction

@Override
protected Object doGetTransaction() {
    DataSourceTransactionObject txObject = new DataSourceTransactionObject();
    txObject.setSavepointAllowed(isNestedTransactionAllowed());
    ConnectionHolder conHolder =
        (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
    txObject.setConnectionHolder(conHolder, false);
    return txObject;
}

(2)doBegin

@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    Connection con = null;
    try {
        if (!txObject.hasConnectionHolder() ||
            txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
            //從DataSource里獲取一個(gè)連接(這個(gè)DataSource一般是有連接池的)
            Connection newCon = obtainDataSource().getConnection();
            if (logger.isDebugEnabled()) {
                logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
            }
            // 把這個(gè)連接用ConnectionHolder包裝一下
            txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
        }
        txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
        con = txObject.getConnectionHolder().getConnection();
        // 設(shè)置isReadOnly、設(shè)置隔離界別等
        Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
        txObject.setPreviousIsolationLevel(previousIsolationLevel);
        //這里非常的關(guān)鍵,先看看Connection 是否是自動(dòng)提交的
		//如果是 就con.setAutoCommit(false)  要不然數(shù)據(jù)庫默認(rèn)沒執(zhí)行一條SQL都是一個(gè)事務(wù),就沒法進(jìn)行事務(wù)的管理了
        //因此從這后面,通過此Connection執(zhí)行的所有SQL語句只要沒有commit就都不會(huì)提交給數(shù)據(jù)庫的
        if (con.getAutoCommit()) {
            txObject.setMustRestoreAutoCommit(true);
            if (logger.isDebugEnabled()) {
                logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
            }
            con.setAutoCommit(false);
        }
        //這個(gè)方法特別特別有意思   它自己`Statement stmt = con.createStatement()`拿到一個(gè)Statement
        // 然后執(zhí)行了一句SQL:`stmt.executeUpdate("SET TRANSACTION READ ONLY");`
        // 所以,所以:如果你僅僅只是查詢。把事務(wù)的屬性設(shè)置為readonly=true  Spring對(duì)幫你對(duì)SQl進(jìn)行優(yōu)化的
        // 需要注意的是:readonly=true 后,只能讀,不能進(jìn)行dml操作)(只能看到設(shè)置事物前數(shù)據(jù)的變化,看不到設(shè)置事物后數(shù)據(jù)的改變)
        prepareTransactionalConnection(con, definition);
        txObject.getConnectionHolder().setTransactionActive(true);
        int timeout = determineTimeout(definition);
        if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
            txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
        }
        // 這一步:就是把當(dāng)前的連接和當(dāng)前的線程進(jìn)行綁定
        if (txObject.isNewConnectionHolder()) {
            TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
        }
    }
    catch (Throwable ex) {
        //如果是新創(chuàng)建的連接,那就釋放
        if (txObject.isNewConnectionHolder()) {
            DataSourceUtils.releaseConnection(con, obtainDataSource());
            txObject.setConnectionHolder(null, false);
        }
        throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
    }
}

(3)doCommit

@Override
protected void doCommit(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    if (status.isDebug()) {
        logger.debug("Committing JDBC transaction on Connection [" + con + "]");
    }
    try {
        con.commit();
    }
    catch (SQLException ex) {
        throw new TransactionSystemException("Could not commit JDBC transaction", ex);
    }
}

到此這篇關(guān)于Java中SpringBoot的@Transactional原理的文章就介紹到這了,更多相關(guān)SpringBoot的@Transactional原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中為什么this可以調(diào)用當(dāng)前實(shí)例

    Java中為什么this可以調(diào)用當(dāng)前實(shí)例

    本文主要介紹了為什么可以通過this關(guān)鍵字訪問到當(dāng)前對(duì)象呢,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • MybatisPlus 多租戶架構(gòu)(Multi-tenancy)實(shí)現(xiàn)詳解

    MybatisPlus 多租戶架構(gòu)(Multi-tenancy)實(shí)現(xiàn)詳解

    這篇文章主要介紹了MybatisPlus 多租戶架構(gòu)(Multi-tenancy)實(shí)現(xiàn)詳解,詳細(xì)的介紹了什么是多租戶架構(gòu)以及使用MybatisPlus實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-11-11
  • SpringBoot啟動(dòng)報(bào)錯(cuò)屬性循環(huán)依賴報(bào)錯(cuò)問題的解決

    SpringBoot啟動(dòng)報(bào)錯(cuò)屬性循環(huán)依賴報(bào)錯(cuò)問題的解決

    這篇文章主要介紹了SpringBoot啟動(dòng)報(bào)錯(cuò)屬性循環(huán)依賴報(bào)錯(cuò)問題的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • java線程安全鎖ReentrantReadWriteLock原理分析readLock

    java線程安全鎖ReentrantReadWriteLock原理分析readLock

    這篇文章主要為大家介紹了java線程安全鎖ReentrantReadWriteLock原理分析readLock,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • mybatis中resultMap 標(biāo)簽的使用教程

    mybatis中resultMap 標(biāo)簽的使用教程

    resultMap 標(biāo)簽用來描述如何從數(shù)據(jù)庫結(jié)果集中來加載對(duì)象,這篇文章重點(diǎn)給大家介紹mybatis中resultMap 標(biāo)簽的使用,感興趣的朋友一起看看吧
    2018-07-07
  • Springcloud中Feign傳遞參數(shù)的過程解析

    Springcloud中Feign傳遞參數(shù)的過程解析

    這篇文章主要介紹了Springcloud中Feign傳遞參數(shù)的過程,單個(gè)參數(shù)的傳值有兩種方式,第一種使用@RequestParam/@PathVariable進(jìn)行傳值,傳遞多個(gè)參數(shù):多個(gè)參數(shù)的傳值可以使用多個(gè)@RequestParam來進(jìn)行傳參,需要的朋友可以參考下
    2023-09-09
  • 圖書管理系統(tǒng)java版

    圖書管理系統(tǒng)java版

    這篇文章主要為大家詳細(xì)介紹了java版的圖書管理系統(tǒng),通過實(shí)例為大家快速掌握數(shù)據(jù)庫編程技術(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Java探索之Thread+IO文件的加密解密代碼實(shí)例

    Java探索之Thread+IO文件的加密解密代碼實(shí)例

    這篇文章主要介紹了Java探索之Thread+IO文件的加密解密代碼實(shí)例,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-10-10
  • java設(shè)計(jì)模式之工廠模式詳解

    java設(shè)計(jì)模式之工廠模式詳解

    本文介紹了三種常見的設(shè)計(jì)模式:簡(jiǎn)單廠模式、工廠方法模式和抽象工廠模式,簡(jiǎn)單廠模式通過一個(gè)工廠類來生產(chǎn)不同的產(chǎn)品實(shí)例,例如同時(shí)生產(chǎn)華為和小米手機(jī),工廠方法模式則通過定義一個(gè)創(chuàng)建對(duì)象的接口,讓子類決定實(shí)例化哪一個(gè)類
    2024-11-11
  • Java中的IO流之字符流Reader和Writer

    Java中的IO流之字符流Reader和Writer

    這篇文章主要介紹了Java中的IO流之字符流Reader和Writer,Reader : 和InputStream的唯一的區(qū)別就在于讀的數(shù)據(jù)單位不同,繼承自Reader的流都是用于向程序中輸入數(shù)據(jù),且數(shù)據(jù)的單位為字符16bit,需要的朋友可以參考下
    2023-10-10

最新評(píng)論