文章目录
前言
在Spring项目中我们通产只需要在启动类上通过@EnableTransactionManagement 开启事务,然后在我们需要增加事务的类/方法上增加@Transactional 注解接口,那么Spring 底层对于事务是如何实现的。
一、Spring 的事务:
Spring的事务管理是一个在Spring框架中用于简化事务操作和管理事务的一致性编程模型。Spring提供了对声明式事务管理的支持,这意味着你可以通过配置来管理事务,而不是在代码中显式地管理。Spring还提供了编程式事务管理,允许开发者通过编码的方式来控制事务的精确性。
二、事务源码解读:
2.1 准备工作:
启动类上增加开启事务管理的注解:用于扫描和解析Advisor 切面以及对代理的方法进行拦截
@EnableTransactionManagement
定义事务管理器:用于生成数据库的连接,提交和回滚事务
@Bean
public DataSourceTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
在需要的类(必须能够被spring 扫描到的bean)或者类中的方法增加注解@Transactional:标记哪些方法需要被代理:
@Transactional(rollbackFor = Exception.class)
public void test() {
xxxService.a();
}
@Transactional(rollbackFor = Exception.class)
public void a() {
}
2.源码解析:
思路:被@Transactional 标注的事务方法中,执行多个sql ,默认情况下 每个SQL 都是一个单独的事务,要想这些sql 同时成功或者失败,就需要保证多个sql 在同一个sql连接中执行;所以需要保证在进入事务方法之前就已经取的了一个连接,然后所有sql 的执行都使用改连接,从而实现多条sql 同时成功或者失败;
我们知道Spring 中事务的实现是通过aop 进行的,那么在进入方法之前生成的连接就应该传递到方法内部的,这样才能保证用的是一个连接,而且对于不同的线程来说事务是隔离的,所以此时就需要使用ThreadLocal对连接进行传递;知道了原理接下来就看下Spring 中是如何完成对 已经存在的类和方法 生成代理对象,并且如何执行事务方法,并且如何进行提交和回滚的;
2.1 Spring 对于事务类和方法的匹配:
首先我们从 @EnableTransactionManagement 进入 :
@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 Integer.MAX_VALUE;
}
可以看到 处理定义了一些属性外,还导入了另外一个类的bean :TransactionManagementConfigurationSelector;这里注意下AdviceMode 的模式是PROXY
即可,接下来进入到 TransactionManagementConfigurationSelector 中;
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
public TransactionManagementConfigurationSelector() {
}
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
// 默认就是使用的 PROXY
return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[]{this.determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return ClassUtils.isPresent("javax.transaction.Transactional", this.getClass().getClassLoader()) ? "org.springframework.transaction.aspectj.AspectJJtaTransactionManagementConfiguration" : "org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration";
}
}
在该类中我们看到返回了一个数组,数组里放入了两个类的class 对象,这里分别对两个类做大概介绍,具体的实现可以进行向下:
- AutoProxyRegistrar: 注册AutoProxyRegistrar bean 调用 registerBeanDefinitions 接口 向spring 注册一个类向为
InfrastructureAdvisorAutoProxyCreator 的 bean,通过改bean 的 后置处理可以扫描并获取到所有的advisor
,注意注册的这个bean 只会发现注册advisor 但是并不会解析@Aspect 相当于开aop 帮助其进行对应advisor 的注册; - ProxyTransactionManagementConfiguration : 注册了3个bean,
这里主要实现对spring 中的bean 和方法 进行匹配,从而确定类中的哪些方法需要被增强,以及实现了具体的增强逻辑
;
对于AutoProxyRegistrar 只是来发现 Spring 事务代理对象(如果对其感兴趣可以参考之前的文章:Spring-Aop 底层源码解析–Spring中Aspect切面逻辑的实现);ProxyTransactionManagementConfiguration 才是真正实现代理逻辑的地方,所以重点关注下:
@Configuration(
proxyBeanMethods = false
)
@Role(2)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
public ProxyTransactionManagementConfiguration() {
}
@Bean(
name = {"org.springframework.transaction.config.internalTransactionAdvisor"}
)
@Role(2)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
// 解析 @Transactional注解 AnnotationTransactionAttributeSource
advisor.setTransactionAttributeSource(transactionAttributeSource);
// 设置advisor 为 transactionInterceptor (事务拦截器)
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder((Integer)this.enableTx.getNumber("order"));
}
return advisor;
}
// TransactionAttributeSource 解析 @Transactional注解
@Bean
@Role(2)
public TransactionAttributeSource transactionAttributeSource() {
//AnnotationTransactionAttributeSource中定义了一个Pointcut
// 并且AnnotationTransactionAttributeSource可以用来解析@Transactional注解
// 并得到一个RuleBasedTransactionAttribute对象
return new AnnotationTransactionAttributeSource();
}
// 定义了一个事务拦截器,进aop 对方法进行事务的增强处理
@Bean
@Role(2)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
这里注册的3个bean 各司其职,注释里已经把它们的作用 做了大概的介绍,其中需要去看的是 BeanFactoryTransactionAttributeSourceAdvisor 其实现了对于类和方法的匹配,TransactionInterceptor 实现了具体的事务实现
;接下来重点对这2个类进行解析;
(1) BeanFactoryTransactionAttributeSourceAdvisor 对于类和方法的匹配逻辑:
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
@Nullable
private TransactionAttributeSource transactionAttributeSource;
// pointcut 定义
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
// 解析事务的工具类
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return BeanFactoryTransactionAttributeSourceAdvisor.this.transactionAttributeSource;
}
};
public BeanFactoryTransactionAttributeSourceAdvisor() {
}
public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
this.transactionAttributeSource = transactionAttributeSource;
}
public void setClassFilter(ClassFilter classFilter) {
this.pointcut.setClassFilter(classFilter);
}
// pointcut 获取
public Pointcut getPointcut() {
return this.pointcut;
}
}
上面代码只是定义了Pointcut ,而Pointcut 内部才匹配的逻辑,所以继续跟下:这里进入到TransactionAttributeSourcePointcut类
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
protected TransactionAttributeSourcePointcut() {
// 类型匹配器
this.setClassFilter(new TransactionAttributeSourceClassFilter());
}
// 方法匹配器
public boolean matches(Method method, Class<?> targetClass) {
// 获取到在 ProxyTransactionManagementConfiguration 类中定义的
// TransactionAttributeSource 的bean 对象
TransactionAttributeSource tas = this.getTransactionAttributeSource();
// AbstractFallbackTransactionAttributeSource 下的 getTransactionAttribute 方法
// getTransactionAttribute 方法进行匹配 判断方法上有 Transactional注解
// 并且对其进行解析并且获取到注解的属性,如果属性不为空则返回true 否则返回false
// 对属性解析封装为 RuleBasedTransactionAttribute 对象
return tas == null || tas.getTransactionAttribute(method, targetClass) != null;
}
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
} else if (!(other instanceof TransactionAttributeSourcePointcut)) {
return false;
} else {
TransactionAttributeSourcePointcut otherPc = (TransactionAttributeSourcePointcut)other;
return ObjectUtils.nullSafeEquals(this.getTransactionAttributeSource(), otherPc.getTransactionAttributeSource());
}
}
public int hashCode() {
return TransactionAttributeSourcePointcut.class.hashCode();
}
public String toString() {
return this.getClass().getName() + ": " + this.getTransactionAttributeSource();
}
@Nullable
protected abstract TransactionAttributeSource getTransactionAttributeSource();
private class TransactionAttributeSourceClassFilter implements ClassFilter {
private TransactionAttributeSourceClassFilter() {
}
// TransactionAttributeSourceClassFilter 类型匹配器
public boolean matches(Class<?> clazz) {
if (!TransactionalProxy.class.isAssignableFrom(clazz) && !TransactionManager.class.isAssignableFrom(clazz) && !PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
// 获取到在 ProxyTransactionManagementConfiguration 类中定义的
// TransactionAttributeSource 的bean 对象
TransactionAttributeSource tas = TransactionAttributeSourcePointcut.this.getTransactionAttributeSource();
return tas == null || tas.isCandidateClass(clazz);
} else {
return false;
}
}
}
}
这个类中就对于类 和方法的匹配进行了实现,注释已经说明,到这里实际上就已经完成了确定Spring 中哪些方法需要被代理增强;当然这里面还有类和方法的具体匹配逻辑,需要的小伙伴可以解析往下看,当然也可以跳过此部分直接进入:2.2 Spring 对于事务方法切面逻辑的增强
。
总结一下:
当某个bean 在生成时如:xxxUserservice 则会通过 ProxyTransactionManagementConfiguration 进行类和方法的匹配,如果匹配则增加相应的advisor 增强逻辑,当某个类或者方法增加 了@Transactional 注解则执行方法之前会进入到 TransactionInterceptor 类中的 invoke 方法中,去执行方法增强的逻辑:
(2) 类和方法的匹配:
(2.1) 类的匹配:
这里我们想看类是怎么匹配的,其主要的实现逻辑在tas.isCandidateClass(clazz) 方法中:这里会进入到AnnotationTransactionAttributeSource
public boolean isCandidateClass(Class<?> targetClass) {
Iterator var2 = this.annotationParsers.iterator();
TransactionAnnotationParser parser;
do {
if (!var2.hasNext()) {
return false;
}
// TransactionAnnotationParser 实现类 SpringTransactionAnnotationParser
// 解析器进行匹配
parser = (TransactionAnnotationParser)var2.next();
} while(!parser.isCandidateClass(targetClass));
return true;
}
可以看到 使用了parser 解析器去进行了一波解析工作,此时进入到SpringTransactionAnnotationParser 中的 isCandidateClass:
public boolean isCandidateClass(Class<?> targetClass) {
// 类上是否有 Transactional 注解
return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
}
这里可以比较直观的看到其判断了类上是否标注 Transactional 注解;
(2.2) 方法的匹配:
方法的匹配逻辑 在getTransactionAttributeSource 方法中 对应的类是AbstractFallbackTransactionAttributeSource
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
} else {
Object cacheKey = this.getCacheKey(method, targetClass);
// 获取 Transactional注解中的属性 并进行缓存
TransactionAttribute cached = (TransactionAttribute)this.attributeCache.get(cacheKey);
if (cached != null) {
return cached == NULL_TRANSACTION_ATTRIBUTE ? null : cached;
} else {
// 获取方法上 @Transactional 住的属性后封装成 TransactionAttribute 对象
TransactionAttribute txAttr = this.computeTransactionAttribute(method, targetClass);
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
} else {
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
DefaultTransactionAttribute dta = (DefaultTransactionAttribute)txAttr;
dta.setDescriptor(methodIdentification);
dta.resolveAttributeStrings(this.embeddedValueResolver);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
// 返回 Transactional注解 注解的属性
return txAttr;
}
}
}
方法匹配器是最终返回某个方法上的TransactionAttribute 对象,详细的实现在 computeTransactionAttribute 中,对 @Transactional 进行解析这里不在跟进了; 这里如果方法上如果 @Transactional 则返回封装好的属性对象 如果没有则返回null;
2.2 Spring 对于事务方法切面逻辑的增强:
(1) 铺垫:
切面逻辑的方法是由 TransactionInterceptor 中的invoke 来具体完成的,这里不仅会开启事务生成连接,并且传递连接,并且会对嵌套方法如 a()->b()->a() 的事务传递进行实现,以及最后事务的提交和回滚;此章节我们主要对事务的开启以及数据库连接的生成做分析;
下面是 TransactionInterceptor 的invoke 方法:
@Nullable
public Object invoke(final MethodInvocation invocation) throws Throwable {
// 获取到被代理类
Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;
// 增强逻辑的进入
// 通过Spring的事务管理器创建一个连接;设置连接的自动提交属性为false;将数据库连接放入到ThreadLocal
// 从ThreadLocal 获取链接, 执行目标的方法,获取链接是从 ThreadLocalMap 获取连接使用的key
//需要是同一个 dataSource 这样set 和get 获取到的连接才能是同一个对象
// 设置隔离级别到 连接上,@Transactional 如果 不设置隔离级别(Isolation)则使用数据库的默认隔离级别
// 执行成功提交事务,失败回滚事务
return this.invokeWithinTransaction(invocation.getMethod(), targetClass, new TransactionAspectSupport.CoroutinesInvocationCallback() {
@Nullable
public Object proceedWithInvocation() throws Throwable {
// 执行后续的 Interceptor
return invocation.proceed();
}
public Object getTarget() {
return invocation.getThis();
}
public Object[] getArguments() {
return invocation.getArguments();
}
});
}
这里最主要的方法 invokeWithinTransaction
这里开启了事务,以及对事务进行了具体的实现,在进入该方法之前,我们先梳理一下两种比较常见的事务逻辑实现方式,便于后面对于代码的解读;
- 场景1 :test 方法 中在调用 a 方法 (a 方法中需要新开启一个事务),实现的思路:
执行a 方法新开一个事务,需要新建立一个数据库连接 并设置隔离级别,然后使用这个新的连接执行sql;
因为最终还要回到test 方法中继续执行sql ,所以需要将之前test 方法中的事务资源先存入到一个地方;在Spring 中的实现方式是ThreadLocalMap 获取到之前的连接,然后生成一个挂起对象,将挂起对象放入到新的事务连接资源中;
清除 ThreadLocalMap 重新生成连接并将连接放入到ThreadLocalMap 中 key 使用同一个dataSource 对象;
a 方法执行完毕后,回到test 方法中,获取到之前挂起事务的资源进行恢复,继续执行 test 中的sql ;
场景1 中 test 方法和a 方法实际上各自创建了一个连接,下面是测试的结果:
可以看到进入test 方法 总共用了3个连接,但是到达a 方法是总共用 使用了4个连接;
- 场景2:执行a 方法,a方法也有事务 需要合并事务实现的思路:
因为在test 方法中已经获取到了一个连接,所以在a方法中也使用这个连接 就可以;
场景2 中 test 方法和a 方法实际上使用了同一个连接,下面是测试的结果:
可以看到test 方法 总共用了3个连接,到达a 方法是同样总共使用了3个连接;
(2) 事务的实现:
事务的逻辑实现主要是在 invokeWithinTransaction 方法中:
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable {
// 获取 @Transactional 注解的属性
TransactionAttributeSource tas = this.getTransactionAttributeSource();
TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null;
// 获取Spring 中定义的事务管理器 DataSourceTransactionManager
TransactionManager tm = this.determineTransactionManager(txAttr);
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
boolean isSuspendingFunction = KotlinDetector.isSuspendingFunction(method);
boolean hasSuspendingFlowReturnType = isSuspendingFunction && "kotlinx.coroutines.flow.Flow".equals((new MethodParameter(method, -1)).getParameterType().getName());
if (isSuspendingFunction && !(invocation instanceof CoroutinesInvocationCallback)) {
throw new IllegalStateException("Coroutines invocation not supported: " + method);
} else {
CoroutinesInvocationCallback corInv = isSuspendingFunction ? (CoroutinesInvocationCallback)invocation : null;
ReactiveTransactionSupport txSupport = (ReactiveTransactionSupport)this.transactionSupportCache.computeIfAbsent(method, (key) -> {
Class<?> reactiveType = isSuspendingFunction ? (hasSuspendingFlowReturnType ? Flux.class : Mono.class) : method.getReturnType();
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(reactiveType);
if (adapter == null) {
throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " + method.getReturnType());
} else {
return new ReactiveTransactionSupport(adapter);
}
});
InvocationCallback callback = invocation;
if (corInv != null) {
callback = () -> {
return CoroutinesUtils.invokeSuspendingFunction(method, corInv.getTarget(), corInv.getArguments());
};
}
Object result = txSupport.invokeWithinTransaction(method, targetClass, callback, txAttr, (ReactiveTransactionManager)tm);
if (corInv != null) {
Publisher<?> pr = (Publisher)result;
return hasSuspendingFlowReturnType ? TransactionAspectSupport.KotlinDelegate.asFlow(pr) : TransactionAspectSupport.KotlinDelegate.awaitSingleOrNull(pr, corInv.getContinuation());
} else {
return result;
}
}
} else {
// 获取 PlatformTransactionManager 事务管理器
PlatformTransactionManager ptm = this.asPlatformTransactionManager(tm);
// 获取方法的名称 作为事务的名称
String joinpointIdentification = this.methodIdentification(method, targetClass, txAttr);
if (txAttr != null && ptm instanceof CallbackPreferringPlatformTransactionManager) {
// 如果 PlatformTransactionManager 是拥有回调功能则进入
ThrowableHolder throwableHolder = new ThrowableHolder();
Object result;
try {
result = ((CallbackPreferringPlatformTransactionManager)ptm).execute(txAttr, (statusx) -> {
TransactionInfo txInfo = this.prepareTransactionInfo(ptm, txAttr, joinpointIdentification, statusx);
Object var9;
try {
Object retVal = invocation.proceedWithInvocation();
if (retVal != null && vavrPresent && TransactionAspectSupport.VavrDelegate.isVavrTry(retVal)) {
retVal = TransactionAspectSupport.VavrDelegate.evaluateTryFailure(retVal, txAttr, statusx);
}
var9 = retVal;
return var9;
} catch (Throwable var13) {
if (txAttr.rollbackOn(var13)) {
if (var13 instanceof RuntimeException) {
throw (RuntimeException)var13;
}
throw new ThrowableHolderException(var13);
}
throwableHolder.throwable = var13;
var9 = null;
} finally {
this.cleanupTransactionInfo(txInfo);
}
return var9;
});
} catch (ThrowableHolderException var22) {
throw var22.getCause();
} catch (TransactionSystemException var23) {
if (throwableHolder.throwable != null) {
this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
var23.initApplicationException(throwableHolder.throwable);
}
throw var23;
} catch (Throwable var24) {
if (throwableHolder.throwable != null) {
this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw var24;
}
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
} else {
return result;
}
} else {
// 如果需要的话开启一个事务 得到txInfo 当前方法线程的事务资源对象
TransactionInfo txInfo = this.createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// 执行目标方法,继续向后执行Interceptor
retVal = invocation.proceedWithInvocation();
} catch (Throwable var20) {
// 发生异常进行回滚,然后抛出异常
this.completeTransactionAfterThrowing(txInfo, var20);
throw var20;
} finally {
// 事务资源的清除
this.cleanupTransactionInfo(txInfo);
}
if (retVal != null && vavrPresent && TransactionAspectSupport.VavrDelegate.isVavrTry(retVal)) {
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = TransactionAspectSupport.VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
// 没有异常则提交事务
this.commitTransactionAfterReturning(txInfo);
return retVal;
}
}
}
可以看到这个方法还是非常长的,因为我么使用的事务管理器是DataSourceTransactionManager , 我们需要关注的是最后一个else 中的方法逻辑,改逻辑中包含了获取一个线程的事务资源,然后执行目标方法,如果成功则进行提交,失败则进行回滚;其中事务资源的获取和封装都是通过 createTransactionIfNecessary 方法进行的,这个章节主要对它 进行分析,事务的提交和回滚我们放大 下一个小章节 2.3 Spring 对于事务执行完毕后的提交和回滚
进行讨论;
createTransactionIfNecessary 去获取当前线程的事务资源:
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
if (txAttr != null && ((TransactionAttribute)txAttr).getName() == null) {
// 如果事务的名字是空的 则将方法的名称设置为事务的名称
txAttr = new DelegatingTransactionAttribute((TransactionAttribute)txAttr) {
public String getName() {
return joinpointIdentification;
}
};
}
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
// 通过事务管理器 开启事务
status = tm.getTransaction((TransactionDefinition)txAttr);
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured");
}
}
return this.prepareTransactionInfo(tm, (TransactionAttribute)txAttr, joinpointIdentification, status);
}
上面的方法没什么逻辑,继续向下看 getTransaction 获取事务方法:
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
// def 事务注解对象
TransactionDefinition def = definition != null ? definition : TransactionDefinition.withDefaults();
// 每次调用 @Transactional 方法都new一个新的DataSourceTransactionObject 对象
Object transaction = this.doGetTransaction();
boolean debugEnabled = this.logger.isDebugEnabled();
if (this.isExistingTransaction(transaction)) {
// 是否存在一个事务,存在则调 handleExistingTransaction,
return this.handleExistingTransaction(def, transaction, debugEnabled);
} else if (def.getTimeout() < -1) {
// 不存在事务,@Transactional 是否定义了Timeout 属性 如果设置了则不能小于默认值
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
} else if (def.getPropagationBehavior() == 2) {
// 如果不存在事务 并且 @Transactional 传播的机制是 必须要先有一个活页的事务,如果没有抛出异常
throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");
} else if (def.getPropagationBehavior() != 0 && def.getPropagationBehavior() != 3 && def.getPropagationBehavior() != 6) {
// 当前事务为 1 SUPPORTS 如果当前存在事务,加入该事务;如果没有,也可以不在事务中执行(不会创建事务)
// 当前事务为 4 NOT_SUPPORTED 不应该在事务环境下运行,如果有活动事务,将其挂起
// 当前事务为 5 NEVER :不应该在事务环境下运行,如果有活动事务,则抛出异常
if (def.getIsolationLevel() != -1 && this.logger.isWarnEnabled()) {
this.logger.warn("Custom isolation level specified but no actual transaction initiated; isolation level will effectively be ignored: " + def);
}
boolean newSynchronization = this.getTransactionSynchronization() == 0;
return this.prepareTransactionStatus(def, (Object)null, true, newSynchronization, debugEnabled, (Object)null);
} else {
// 当前没有事务 要求新建一个事务
// 事务的传播机制是 REQUIRED(0),:如果当前存在事务,加入该事务;如果当前没有事务,则创建一个新的事务
// REQUIRES_NEW(3),创建一个新的事务,如果当前已存在事务,把当前事务挂起
// NESTED(6)如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则表现如 REQUIRED
// 将当前的数据资源 放入到挂起的 suspendedResources 对象中
// 第一次调用 直接返回null 不挂起资源
SuspendedResourcesHolder suspendedResources = this.suspend((Object)null);
if (debugEnabled) {
this.logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
try {
// 开启一个事务 并返回一个 TransactionStatus 对象,改对象中也放入了 被挂起的资源
return this.startTransaction(def, transaction, debugEnabled, suspendedResources);
} catch (Error | RuntimeException var7) {
this.resume((Object)null, suspendedResources);
throw var7;
}
}
}
上面的代码虽然已经进行了注释,但是还是需要进行一下拆分,来查看它们的没部分作用:
(1) doGetTransaction()获取 DataSourceTransactionObject 事务资源对象:
protected Object doGetTransaction() {
// 每次调用都新建一个 DataSourceTransactionObject 对象
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
// obtainDataSource 获取dataSource 对象
// getResource从当前线程 去拿 key 为dataSource value 为 ConnectionHolder 的对象
// 如果有值则拿到,没有则返回null
ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.obtainDataSource());
// 设置conHolder ,false:表示 conHolder 不是新建的
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
protected DataSource obtainDataSource() {
DataSource dataSource = this.getDataSource();
Assert.state(dataSource != null, "No DataSource set");
return dataSource;
}
@Nullable
public static Object getResource(Object key) {
// 重新将dataSource 对象 获取一个新的key
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
return doGetResource(actualKey);
}
@Nullable
private static Object doGetResource(Object actualKey) {
// private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal("Transactional resources");
// 从当前线程获 key 为dataSource 对象 value为 ConnectionHolder 对象
Map<Object, Object> map = (Map)resources.get();
if (map == null) {
return null;
} else {
Object value = map.get(actualKey);
if (value instanceof ResourceHolder && ((ResourceHolder)value).isVoid()) {
map.remove(actualKey);
if (map.isEmpty()) {
resources.remove();
}
value = null;
}
return value;
}
}
可以看到没进入一个事务方法doGetTransaction 都新建一个 DataSourceTransactionObject 对象,然后获取当前线程的事务资源 进行设置后进行了返回;
显然通过doGetTransaction 方法 获取到了当前线程的事务资源对象;
(2)首先看下最后的else 逻辑,这里实现了 当前没有事务 新建一个事务:
改方法中首先调用了this.suspend((Object)null) 对当前线程的是我资源进行挂起,因为当前线程没有事务资源,此方法传入null 值,在挂起方法suspend 中如果当前线程事务资源是null 实际上什么也没做,个人认为这行代码可以完全删除;
重点关注下 startTransaction
方法开启一个新的事务:
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
// 是否要开启一个新的事务
boolean newSynchronization = this.getTransactionSynchronization() != 2;
// 事务的状态信息,包括事务的定义,保存数据库连接的对象,是否是新事务,
// 是否是新的TransactionSynchronization
DefaultTransactionStatus status = this.newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 开启事务
this.doBegin(transaction, definition);
// 如果需要新开一个TransactionSynchronization ,
// 就把新创建事务的状态信息设置到 TransactionSynchronizationManager
this.prepareSynchronization(status, definition);
return status;
}
改方法里又通过doBegin 方法去开启事务,并把新开启的事务的属性进一步封装为 TransactionStatus 对象进行了返回,接下来进入进入到 DataSourceTransactionManager 下的 doBegin 方法:
protected void doBegin(Object transaction, TransactionDefinition definition) {
// 创建事务资源对象
DataSourceTransactionObject txObject = (DataSourceTransactionObject)transaction;
Connection con = null;
try {
// 如果 当前没有事务(没有数据库连接)
if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
// 通过dataSource 获取到一个连接对象
Connection newCon = this.obtainDataSource().getConnection();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
// 封装连接对象为 ConnectionHolder,获取到了一个新连接,并标识该连接是新创建的
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
// 从@Transactional 注解中获取到隔离级别
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
// 设置隔离级别
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// 设置readOnly 属性
txObject.setReadOnly(definition.isReadOnly());
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
// 设置自动提交为 false
con.setAutoCommit(false);
}
//
this.prepareTransactionalConnection(con, definition);
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = this.determineTimeout(definition);
if (timeout != -1) {
// 如果定义了超时时间 ,则设置超时时间
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// 当前的这个连接是否是新建的
if (txObject.isNewConnectionHolder()) {
// 如果是新建的 在将改连接放入到 ThreadLocal 中去key为dataSource
// value 为包装的ConnectionHolder对象
TransactionSynchronizationManager.bindResource(this.obtainDataSource(), txObject.getConnectionHolder());
}
} catch (Throwable var7) {
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, this.obtainDataSource());
txObject.setConnectionHolder((ConnectionHolder)null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", var7);
}
}
改方法中最终实现了 事务资源对象的创建,并且将新创建的事务资源对象与当前线程进行绑定,方法中每行代码都进行了标注;
(3) 如果进入到当前方法之前,当前线程已经存在事务 则进入 handleExistingTransaction 方法中 :
private TransactionStatus handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException {
// 当前线程已经存在了事务使用与 a()->b() ,此时在b () 方法中
if (definition.getPropagationBehavior() == 5) {
// 如果传播机制是 不以事务运行 则报错
throw new IllegalTransactionStateException("Existing transaction found for transaction marked with propagation 'never'");
} else {
// 当前线程事务资源对象 suspendedResources
SuspendedResourcesHolder suspendedResources;
if (definition.getPropagationBehavior() == 4) {
// 如果当前的事务传播是NOT_SUPPORTED 不应该在事务环境下运行,如果有活动事务,将其挂起。
if (debugEnabled) {
this.logger.debug("Suspending current transaction");
}
// 不开启新的事务,把当前事务挂起,清除当前线程 threadLocal 的资源,此时 threadLocal
// 连接资源也会被清除,suspendedResources 为清除之前 线程 threadLocal 事务资源
// 因为清除了threadLocal 的连接,所以在改方法里执行的sql 需要自行重新使用jdbcTemplate 或者mybatis 在自行创建连接
suspendedResources = this.suspend(transaction);
boolean newSynchronization = this.getTransactionSynchronization() == 0;
// 根据当前进入方法 @Transactional 注解的信息重新赋值 ,返回事务的状态对象
return this.prepareTransactionStatus(definition, (Object)null, false, newSynchronization, debugEnabled, suspendedResources);
} else if (definition.getPropagationBehavior() == 3) {
// 如果当前事务传播级别是 REQUIRES_NEW:
// 创建一个新的事务,如果当前已存在事务,把当前事务挂起。
if (debugEnabled) {
this.logger.debug("Suspending current transaction, creating new transaction with name [" + definition.getName() + "]");
}
// 将当前线程事务资源挂起,suspendedResources 为清除之前 线程 threadLocal 事务资源
suspendedResources = this.suspend(transaction);
try {
// 开启一个新的事务改事务包含了被挂起的资源
return this.startTransaction(definition, transaction, debugEnabled, suspendedResources);
} catch (Error | RuntimeException var6) {
this.resumeAfterBeginException(transaction, suspendedResources, var6);
throw var6;
}
} else if (definition.getPropagationBehavior() == 6) {
// 如果传播机制是NESTED:如果当前存在事务,则在嵌套事务内执行。
// 如果当前没有事务,则表现如 REQUIRED
if (!this.isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException("Transaction manager does not allow nested transactions by default - specify 'nestedTransactionAllowed' property with value 'true'");
} else {
if (debugEnabled) {
this.logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
if (this.useSavepointForNestedTransaction()) {
// 如果当前存在事务,则在嵌套事务内执行
DefaultTransactionStatus status = this.prepareTransactionStatus(definition, transaction, false, false, debugEnabled, (Object)null);
// 创建事务保存点savePoint 用于 存储点的回滚,关于存储点可以在 第三 的扩展章节中查看
status.createAndHoldSavepoint();
return status;
} else {
// 当前没有事务 则新建事务
return this.startTransaction(definition, transaction, debugEnabled, (SuspendedResourcesHolder)null);
}
}
} else {
if (debugEnabled) {
this.logger.debug("Participating in existing transaction");
}
if (this.isValidateExistingTransaction()) {
if (definition.getIsolationLevel() != -1) {
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, "ISOLATION_") : "(unknown)"));
}
}
if (!definition.isReadOnly() && TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" + definition + "] is not marked as read-only but existing transaction is");
}
}
// 如果第二个方法依然是 REQUIRED:如果当前存在事务,加入该事务;如果当前没有事务,则创建一个新的事务。
// 什么都不处理,默认是同一个事务
boolean newSynchronization = this.getTransactionSynchronization() != 2;
return this.prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, (Object)null);
}
}
}
这个方法实现多个事务的传播方式的实现,上面已经对每个逻辑进行了标注,这里值对挂起的逻辑进行补充,当前第二个方法需要开启一个新的事务,这个时候就需要对线程中已经存在的事务资源进行挂起;
this.suspend 挂起当前资源:
@Nullable
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
// 判断当前线程是否开启过事务,因为只有开启了事务之后初始化是会将synchronizations 进行空集合的初始化
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// 如果开启过事务 doSuspendSynchronization 获取到自己定义的事务状态监听的方法
// 执行自定义的挂起方法,对于事务状态的流转监听可以在 第三 扩展章节中进行查看
// 返回当前事务资源所有自定义的事务状态 方法
List<TransactionSynchronization> suspendedSynchronizations = this.doSuspendSynchronization();
// 获取之前事务的资源 放入到挂起对象中,并且新开一个事务
try {
Object suspendedResources = null;
if (transaction != null) {
// 当前的事务资源不为 null
// 将当前线程的 资源从ThreadLocal 中移除,并返回改移除的 事务资源对象
suspendedResources = this.doSuspend(transaction);
}
// 将之前的事务 资源的属性拿到,并且重新初始化事务资源属性
String name = TransactionSynchronizationManager.getCurrentTransactionName();
TransactionSynchronizationManager.setCurrentTransactionName((String)null);
boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel((Integer)null);
boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
TransactionSynchronizationManager.setActualTransactionActive(false);
// 创建资源挂起对象,并将之前线程的资源 进行放入(资源和 资源的一些属性)
// 这样返回的对象就包含了之前的事务资源,便于后面事务资源的恢复
return new SuspendedResourcesHolder(suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
} catch (Error | RuntimeException var8) {
this.doResumeSynchronization(suspendedSynchronizations);
throw var8;
}
} else if (transaction != null) {
// 当前已经没有有事务,但是事务资源不为空, 需要将当前事务挂起
// 获取到当前线程事务的资源对象
Object suspendedResources = this.doSuspend(transaction);
return new SuspendedResourcesHolder(suspendedResources);
} else {
return null;
}
}
上面挂起方法主要逻辑就是 如果当前线程已经存在了事务则获取到已存在的事务资源,同时移除线程中老的事务资源,重新生成一个新的事务资源 进行属性的设置,并且将之前的事务资源也放入到新的事务资源中;
2.3 Spring 对于事务执行完毕后的提交和回滚:
(1) 事务的提交:
如果没有发生异常在事务通过commitTransactionAfterReturning 方法, this.commitTransactionAfterReturning(txInfo);
最终进入到AbstractPlatformTransactionManager 类下 commit 方法:
public final void commit(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");
} else {
DefaultTransactionStatus defStatus = (DefaultTransactionStatus)status;
// 事务进行提交
if (defStatus.isLocalRollbackOnly()) {
// 如果事务可以提价但是设置了强制回滚
if (defStatus.isDebug()) {
this.logger.debug("Transactional code has requested rollback");
}
//
this.processRollback(defStatus, false);
} else if (!this.shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
//
if (defStatus.isDebug()) {
this.logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
this.processRollback(defStatus, true);
} else {
// 提交事务
this.processCommit(defStatus);
}
}
}
(2)事务的回滚:
如果事务中出现了异常,则进入到completeTransactionAfterThrowing 方法进行事务的回滚处理;
this.completeTransactionAfterThrowing(txInfo, var20);
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex);
}
// 如果抛出的异常.rollbackOn
// 如果定义 了@Transactional(rollbackFor = Exception.class)
// 先对定义的异常进行 匹配 @Transactional(rollbackFor = Exception.class) 定义的异常
// 如果匹配了则进一步判断 异常是否不是 noRollbackFor 定义的异常 则返回true 否则false
// 如果 @Transactiona 没有定义 rollbackFor
// 则匹配 ex instanceof RuntimeException || ex instanceof Error; 匹配则为true 否则为false
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
} catch (TransactionSystemException var6) {
this.logger.error("Application exception overridden by rollback exception", ex);
var6.initApplicationException(ex);
throw var6;
} catch (Error | RuntimeException var7) {
this.logger.error("Application exception overridden by rollback exception", ex);
throw var7;
}
} else {
try {
// 如果抛出的异常不是需要回滚的异常,则继续提交
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
} catch (TransactionSystemException var4) {
this.logger.error("Application exception overridden by commit exception", ex);
var4.initApplicationException(ex);
throw var4;
} catch (Error | RuntimeException var5) {
this.logger.error("Application exception overridden by commit exception", ex);
throw var5;
}
}
}
}
事务的回滚会先看下咱们在@Transactional(rollbackFor = xxx.class),rollbackFor 定义的异常类,只有抛出的异常时定义的异常类或者是其子类才获取事务管理器对象调用rollback 方法完成回滚,所以在我们平常的业务处理中,我们可以将异常的类型适当放大如定义为:Exception.class 或者Throw.class 关于这两个比较顶级的类的 区别可以参考扩展章节中的3.3 异常处理类Exception 和Throw 的区别
查看;
如果抛出的异常不是我们定义的异常类或者子类此时进入else 方法,继续完成sql的提交;
接下来看下事务进行rollback 回滚的源码:最终会进入到AbstractPlatformTransactionManager 的processRollback:
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected;
try {
// 事务回滚前方法的触发
this.triggerBeforeCompletion(status);
if (status.hasSavepoint()) {
// 如果有保存点
if (status.isDebug()) {
this.logger.debug("Rolling back transaction to savepoint");
}
// 回滚到保存点:
// 如果进入的方法注解定义的是@Transactional(propagation= Propagation.NESTED)
// 嵌套事务,则进入该方法会创建savePoint 点,直接回到savePoint 点
status.rollbackToHeldSavepoint();
} else if (status.isNewTransaction()) {
if (status.isDebug()) {
this.logger.debug("Initiating transaction rollback");
}
// 如果没有保存点,请求是新的事务 ,则将这个事务执行回滚
// 获取事务资源中的连接对象,然后进行回滚
this.doRollback(status);
} else {
// 如果没有保存点,但是不是新的事务(继承上一个方法的事务)
if (status.hasTransaction()) {
// 如果有事务 但时不是新的事务
if (!status.isLocalRollbackOnly() && !this.isGlobalRollbackOnParticipationFailure()) {
// isGlobalRollbackOnParticipationFailure 默认为true
if (status.isDebug()) {
this.logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
}
} else {
if (status.isDebug()) {
this.logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}
// /直接将roLLback0nLy设置到ConnectionHolder中去,表示整个事务的sqL都要回滚
// 部分失败进行全部回滚
// 一个事务中有两个方法,第二个方法抛出异常,那么第一和二方法都进行失败回滚
this.doSetRollbackOnly(status);
}
} else {
this.logger.debug("Should roll back transaction but cannot - no transaction available");
}
if (!this.isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = false;
}
}
} catch (Error | RuntimeException var8) {
this.triggerAfterCompletion(status, 2);
throw var8;
}
this.triggerAfterCompletion(status, 1);
if (unexpectedRollback) {
throw new UnexpectedRollbackException("Transaction rolled back because it has been marked as rollback-only");
}
} finally {
//
this.cleanupAfterCompletion(status);
}
}
上面的每行代码基本都做了注释,大概流程时先进行事务回滚前事件的出发,接下来如果我们定义了保存点,则回滚到最近的保存点;如果没有定义保存点,或者是新的事务,或者继承上一个方法的事务,则将当前线程的事务进行回滚,最好执行事务回滚完成事件的触发;
前面的章节我们看了事务的创建,事务的执行,事务的回滚和提交,接下来对于 test()->a()->test() ,a() 方法完成回到test() 方法,假如此时test() 向下执行的方法中依然是有sql 的此时就需要对事务资源进行恢复,即将当前线程中存储的之前在a()方法中的事务进行清除,然后获取到挂起的事务资源,进行事务的恢复;
2.4 Spring 对于事务执行完毕后事务资源的恢复:
this.cleanupAfterCompletion(status); 方法清除一些资源并恢复被挂起的事务资源;
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
if (status.isNewTransaction()) {
// 如果当前的事务是 进入该方法新建的事务,进入每个方法都会创建一个
// 新的 TransactionStatus 的 status对象,关闭数据库连接
this.doCleanupAfterCompletion(status.getTransaction());
}
// 挂起资源的恢复
if (status.getSuspendedResources() != null) {
if (status.isDebug()) {
this.logger.debug("Resuming suspended transaction after completion of inner transaction");
}
// 获得被挂起的资源
Object transaction = status.hasTransaction() ? status.getTransaction() : null;
// 恢复 将事务资源重新进行恢复
this.resume(transaction, (SuspendedResourcesHolder)status.getSuspendedResources());
}
}
每行都进了注释,主要是处理,如果事务是新建的,则重置当前线程事务,并且或者之前被挂起的事务资源,然后进行恢复;
三、扩展:
3.1 自定义事务状态的监听逻辑:
可以在自己的业务中,监听一个方法执行时,事务的状态流转信息;
@Transactional
public void test() {
userService.a();
System.out.println("test()");
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void suspend() {
// 当前test 方法的事务 被挂起后执行
TransactionSynchronization.super.suspend();
}
@Override
public void resume() {
// 当前test 方法的事务 被挂起恢复后执行
TransactionSynchronization.super.resume();
}
@Override
public void flush() {
TransactionSynchronization.super.flush();
}
@Override
public void beforeCommit(boolean readOnly) {
// 当前test 方法的事务 提交之前
TransactionSynchronization.super.beforeCommit(readOnly);
}
@Override
public void beforeCompletion() {
// 当前test 方法的事务 回滚之前
TransactionSynchronization.super.beforeCompletion();
}
@Override
public void afterCommit() {
// 当前test 方法的事务 提交之后
TransactionSynchronization.super.afterCommit();
}
@Override
public void afterCompletion(int status) {
// 当前test 方法的事务 回滚之后
TransactionSynchronization.super.afterCompletion(status);
}
});
}
3.2 事务中的保存点:
在MySQL中,savepoint(保存点)是事务处理过程中的一个标记点,你可以在事务中创建一个或多个savepoints。如果后续事务处理出现错误或者需要部分撤销操作,可以使用savepoints来回滚事务到特定的点,而不是回滚整个事务。这样可以给予开发者更细粒度的控制权,仅仅回滚事务中的一部分操作。
使用savepoint的步骤通常如下:
(1). 开始一个事务:
sql START TRANSACTION; 或者 BEGIN;
(2). 创建savepoint:
sql SAVEPOINT savepoint_name;
其中 savepoint_name
是你赋予这个savepoint的名字。
(3). 执行一些数据库操作,比如插入、更新或删除数据。
(4). 如果需要回滚到savepoint:
sql ROLLBACK TO savepoint_name;
使用这个命令回滚到之前创建的指定savepoint。
(5). 如果整个事务正常完成,或者在完成稍后的事务操作后:
sql COMMIT;
使用这个命令来提交整个事务,包括所有保存点之后的操作。提交事务会释放在这个事务中定义的所有savepoint。
(6). 如果需要释放savepoint:
sql RELEASE SAVEPOINT savepoint_name;
如果你确定不再需要某个特定的savepoint,可以通过 RELEASE SAVEPOINT
来释放它。如果事务成功提交,所有的savepoint也将自动被释放。
Savepoints 对于复杂的事务管理或者需要条件性回滚的场景非常有用,它们允许根据逻辑决定是否撤销一部分事务,而不是全盘否定所有更改。在编程语言与数据库驱动集成的情况下,如在使用JDBC时,你可以通过编程接口来管理savepoints。
3.3 异常处理类Exception 和 Error的区别:
先看下类图:
从类图中可以清楚的看到 Exception 和Eroor 都继承Throwable 类,对于它们的区别大家也比较属性,一个是运行时的程序异常,比如空指针,数组下标越界,文件无法找到;而Eroor 就是程序的错误,这些通常是由于外部硬件因素的故障,所有如果我们想在发生异常和错误时都不对事务进行回滚,则可以 在事务里catch Throwable :
try {
// do something
}catch (Throwable e){
}
然而,通常我们不建议捕获 Error,因为它们通常指示着更严重的问题,例如 OutOfMemoryError,这些情况下程序可能已经处于不稳定的状态,回滚事务可能无法正常进行。
总结
本文通过从@EnableTransactionManagement 注解开始,一步步去观察事务如何进行开启的,并且事务的类和方法如果进行匹配的以及事务资源的创建,事务的提交和回滚,以及事务资源的挂起和恢复;每个步骤都进行了梳理。