大家基本上都用过事务,今天一起分析下spring源码中也比较重要的一个模块-事务。spring中事务这一块要完全使用好还是有一定难度,主要是很多细节需要注意,如果你还没有完全明白spring的事务,那么这篇文章肯定会让你收获满满。
一、创建代理
spring事务创建代理的流程和spring aop创建代理几乎是一模一样,不清楚的可以自行阅读相关资料或者参考这篇文章(spring aop分析)。这里稍微介绍创建代理之前spring会先创建几个重要的对象
我们从@EnableTransactionManagement这个事务的开关的入口开始
1.@EnableTransactionManagement
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
}
不多讲,直接看@Import里面的类,如果不明白的,可以阅读这篇文章(spring源码解析之ConfigurationClassPostProcessor分析)
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) {
//默认是PROXY,spring会讲该方法返回的string[]都实例化
case PROXY:
return new String[] {
AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {
determineTransactionAspectClass()};
default:
return null;
}
}
//...省略
}
所以到这里,spring会实例化一个AutoProxyRegistrar对象和ProxyTransactionManagementConfiguration对象,其中AutoProxyRegistrar和AOP创建那个拦截是否需要代理的BeanpostProcessor一样,这里就不继续跟,感兴趣自行阅读。我们看ProxyTransactionManagementConfiguration。
3.ProxyTransactionManagementConfiguration
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<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;
}
}
这里会创建三个对应的三个实例
BeanFactoryTransactionAttributeSourceAdvisor:是一个advisor,一般封装advice和pointcut
TransactionAttributeSource:用于解析事务标签属性
TransactionInterceptor:这个最重要,直接就是动态代理的调用的方法,其实现了MethodInterceptor接口。所以当调用生成的动态代理的方法时,会调用到TransactionInterceptor.invoke()方法,这也是我们今天分析的入口。其他的流程和springAOP流程一致,可自行阅读
二、创建事务源码分析
直接从TransactionInterceptor#invoke()开始分析
1.TransactionInterceptor.invoke()
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
直接过,看invokeWithinTransaction
2.TransactionAspectSupport.invokeWithinTransaction()
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
//通过TransactionAttributeSource获取@Transactional注解中的属性
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
//获取事务管理器
final TransactionManager tm = determineTransactionManager(txAttr);
//这个if一般不会走到
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
}
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
//1.这是创建事务的核心逻辑,非常重要
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
//2.调用真是的业务逻辑
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
//3.核心逻辑之一,事务回滚
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);
}
}
//4.核心逻辑之一,事务提交
commitTransactionAfterReturning(txInfo);
return retVal;
}
//...省略代码,暂时先不看
}
事务-主要处理的逻辑如下
创建事务、调用业务逻辑、事务回滚、事务提交我们一个个来看,spring事务中隔离级别和mysql的隔离级别是一致的,但是spring中的传播属性是spring实现的,这就是难点之一,我们今天重点看的是如何正确处理好传播属性。分析之前,先描述下spring支持哪7重传播属性
REQUIRED:如有事务,则使用当前事务,没有则创建
SUPPORTS:如果有事务,就用当前事务;没有则不适用事务
MANDATORY:使用当前事务,如果当前事务没有则抛异常
REQUIRES_NEW:新建事务,如果当前存在事务,则将当前事务挂起
NOT_SUPPORTED:非事务方式执行,如果当前存在事务 ,就将当前事务挂起
NEVER:非事务方式执行,如果当前存在事务 ,就抛异常
NESTED:嵌套事务
其实最常用的就是REQUIRED(默认)、REQUIRES_NEW、NESTED,今天源码分析也只分析上面三种,也是最复杂的三种
本文以我下面的测试的代码为例子,进行分析
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
public void testInsert() throws Exception {
String sql = "insert into user (name,age,sex) values(?,?,?)";
jdbcTemplate.update(sql,new Object[]{
"taott11",12,"man"});
//int a = 1/0;
//throw new Exception();
String sql2 = "insert into user (name,age,sex) values(?,?,?)";
jdbcTemplate.update(sql2,new Object[]{
"tao",18,"woman"});
//这里又调用了另外一个有事务标记的方法(动态代理方法)
productService.queryUesr();
}
@Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.READ_COMMITTED)
public void queryUesr() throws Exception {
query();
throw new RuntimeException();
}
上述实例会调用两次动态代理的方法,一次是UserService.testInsert(),另外一次是ProductService.queryUesr(),请忽略类名和方法名,没任何含义,仅仅是测试使用而已
我们先从第一个代理方法开始进入分析,调用业务方法testInsert()之前先创建事务
3.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;
}
};
}
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
//1.核心逻辑
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
没什么重要的逻辑,我们重点看tm.getTransaction()
4.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());
//1.创建一个事务对象
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
//2.判断是否已经存在事务,第一次调用testInsert没有,第二次就有了,非常重要的方法
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(def, transaction, debugEnabled);
}
// Check definition settings for new transaction.
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
try {
//3.开启事务
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);
}
}
重要的逻辑方法,我已经做了标注了,下面我们一个个看
4-1.doGetTransaction()
创建事务对象
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
//这个地方拿到数据库的连接,其实是从threadlocal中拿,第一次拿不到,因为没有设置进去,后面会详细将
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
//所以这个事务的连接其实是null
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
第一次不会走到上面代码4中的注释2,因为不存在事务。所以我们直接看注释3,开启事务startTransaction
4-2.startTransaction()
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
//创建了一个事务状态,请记住第三个参数为true,后面会用到
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
//开怎么开启事务的
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
这里就是创建了一个DefaultTransactionStatus,这里第三个参数newTransaction=true希望大家先记住,这是spring事务的一个非常重要的细节,后面的提交和回滚都和参数有联系,只有该参数为true的条件下的事务才有资格提交和回滚,下面我们看doBegin
4-2-1.doBegin()
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
//1.给当前事务设置连接
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
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).
//2.必须要关闭自动提交设置手动提交,否则你提交代码就提交了事务
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.
//3.绑定连接
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);
}
}
这里重点的方法都标注出来了,我们一个个看
注释1:给当前事务设置连接,我们之前已经分析了,我们第一次调用testInsert()时,从threadlocal中是没取到ConnectionHolder(其实就是connection的封装),这里就从连接中获取一个connection然后封装成ConnectionHolder设置到事务对象中
注释2:这里就是要跟原生jdbc一样,使用事务,也要先将自动提交设置成手动提交
注释3:这里就比较重要了,其实就是将当前ConnectinoHolder设置到threadlocal中,方便第二个事务调用时能获取到,我们具体看下bindResource()里面的逻辑,还是非常有意思的
4-2-1-1.TransactionSynchronizationManager.bindResource()
public static void bindResource(Object key, Object value) throws IllegalStateException {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Assert.notNull(value, "Value must not be null");
Map<Object, Object> map = resources.get();
// set ThreadLocal Map if none found
if (map == null) {
map = new HashMap<>();
resources.set(map);
}
Object oldValue = map.put(actualKey, value);
// Transparently suppress a ResourceHolder that was marked as void...
if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) {
oldValue = null;
}
if (oldValue != null) {
throw new IllegalStateException("Already value [" + oldValue + "] for key [" +
actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
}
if (logger.isTraceEnabled()) {
logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread [" +
Thread.currentThread().getName() + "]");
}
}
这个方法就是往threadLocal中设置一个Map<Object,Object>,其中key是数据源,value是ConnectionHolder。这里为什么要用Map而不是直接存储ConnectionHolder呢?因为可能存在多数据源的情况,一个方法如果两个数据源不一样,而我们拿到的连接如果是一样的就有问题了。另外设置到threadlocal中,我们在同一个线程中就能获取到上一次存储的ConnectionHolder了。也就是当我们调用第二个事务方法productService.queryUer()方法时,就能获取到存储在ConnectionHolder了(单个数据源情况下)
//———————————————–强行分页—————————————————————//
到这里我们第一个方法userService.testInsert()的事务已经开启了,我们开始调用业务逻辑,而业务逻辑中又会调用ProductService.queryUser(),这又要进入上述的一样的逻辑了。相同的逻辑我就不继续讲了,我们直接将视野看到代码4中(AbstractPlatformTransactionManager.getTransaction),这里有几个地方需要注意
注释1:这里又创建了一个新的事务,但是事务的连接是从threadlocal中拿的,我们这里没有切换数据源,并且第一次调用UserService.testInsert开始事务时已经往threadlocal中设置了connectionHolder,所以我们这里创建的第二个事务是新的,但是连接和上一个连接是一样的
注释2:这里的if会判断为true,会调用一个非常重要的方法handleExistingTransaction(),下面会详细分析,代码不会走到注释3,因为if里面已经return了。开始看handleExistingTransaction
5.handleExistingTransaction()
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
//1.传播属性为PROPAGATION_NEVER
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
//2.传播属性为PROPAGATION_NOT_SUPPORTED
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
//3.传播属性为PROPAGATION_REQUIRES_NEW
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
//4.传播属性为PROPAGATION_NESTED
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
if (useSavepointForNestedTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
status.createAndHoldSavepoint();
return status;
}
else {
// Nested transaction through nested begin and commit/rollback calls.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
return startTransaction(definition, transaction, debugEnabled, null);
}
}
//5.剩下的几种都走下面的逻辑
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
if (isValidateExistingTransaction()) {
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
Constants isoConstants = DefaultTransactionDefinition.constants;
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] specifies isolation level which is incompatible with existing transaction: " +
(currentIsolationLevel != null ?
isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
"(unknown)"));
}
}
if (!definition.isReadOnly()) {
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] is not marked as read-only but existing transaction is");
}
}
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
//6.要特别注意第三个参数了为newTransaction=false
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
代码虽然很长,但是比较容易,无非就是根据上面的几种不同的传播属性,做不同的逻辑。本文重点分析常用的几种传播属性REQUIRED、REQUIRES_NEW、NESTED,其他的几种也很简单,大家自行分析。
先看REQUIRED,比较见到,看最下面一行就行了
5-1.REQUIRED
//要特别注意第三个参数了为newTransaction=false
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
创建了一个事务状态,但是它的newTransaction=false,也就是它没有资格真正的回滚和提交后面会详细讲
5-2.REQUIRES_NEW
直接看上面的注释3
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
//1.会把上一个事务给挂起
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
//2.开始事务
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
注释1:将上一个事务挂起,下面会分析
注释2:开始新的事务,这个地方和之前开启事务的逻辑一样,重新设置连接、将连接设置到threadlocal中、将自动提交设置成手动提交
下面我们看下注释1是如何挂起事务的
5-2-1.suspend
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
Object suspendedResources = null;
if (transaction != null) {
//1.重点挂起的逻辑
suspendedResources = doSuspend(transaction);
}
String name = TransactionSynchronizationManager.getCurrentTransactionName();
TransactionSynchronizationManager.setCurrentTransactionName(null);
boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
TransactionSynchronizationManager.setActualTransactionActive(false);
//2.返回一个对象,该对象封装了被挂起的事务信息,方便后面能重新拿得到
return new SuspendedResourcesHolder(
suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
}
//...省
}
接着看注释1的逻辑doSuspend
5-2-1-1.doSuspend
protected Object doSuspend(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
//将当前事务对象connection设置成null
txObject.setConnectionHolder(null);
//解绑,其实就是从threadlocal中删除Map
return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
因为创建第二个事务的时候,会将第一个事务的connectionHolder设置进来,这里挂起的操作,就是将第一次设置到threadlocal中的connectionHolder删除掉,并且将当前事务的connection设置成null。然后上面代码5-2.REQUIRES_NEW中的注释2中开启事务startTransaction方法,会将新的connectionHolder设置到threadlocal中,注意,此时startTransaction生成的事务状态的newTransaction=true
5-3.NESTED
接着来看第二个事务是嵌套事务的情况
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
if (useSavepointForNestedTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
//1.创建事务状态
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
//2.创建回滚点
status.createAndHoldSavepoint();
return status;
}
else {
// Nested transaction through nested begin and commit/rollback calls.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
return startTransaction(definition, transaction, debugEnabled, null);
}
}
注释1:创建事务状态,注意此的newTransaction=false
注释2:创建一个回滚点,支持部分回滚,其实就是简单的封装了jdbc,不清楚回滚点的可以自行查阅相关内容
不知不觉已经已经写了很多了,但是这仅仅只是介绍了创建事务的原理,还有事务回滚、事务提交、注意事项都没讲,原本以为一篇文章能全部讲完,但是写太长了怕大家阅读起来比较类有恐惧感,所以我将事务回滚、事务提交、注意事项写在下一篇文章,请移步到(spring源码分析之事务transaction下篇)
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/111198.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...