spring基本使用(15)-springtx的使用以及原理1 基于xml声明式事务原理解析

1、事务的基本知识点:

      1.1、事务的特性:

                 A(原子性 Automic)

                C(一致性 Consistency)

                 I(隔离性 Isolation)

                 D(持久性 Duration)

       1.2、数据并发问题

               1、脏读:A事务读取B事务尚未提交的更改数据。

               2、不可重复读:同一个事务中,多次查询,可能查询到的值是不一样的。

               3、幻读:A事务读取到了B事务新增的数据。

               4、第一类数据丢失:A事务撤销的时候,把已提交事务的B事务的更新数据覆盖。

               5、第二类更新丢失:A事务覆盖B事务已经提交的数据。

       1.3、事务隔离级别

隔离级别

脏读

幻读

不可重复读

第一类丢失更新

第二类丢失更新

READ_UNCOMMITED

 不会

READ_COMMITED

不会

不会

REPEATABLE READ

不会

不会

不会

不会

SERIALIZABLE

不会

不会

不会

不会

不会

 

2、Spring中事务的传播机制

            

 

3、Spring中基于xml声明事务

    <!-- 事务管理器,依赖于数据源 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
	
    <!-- 编写通知:对事务进行增强(通知),需要编写切入点和具体执行事务的细节,
	      默认的事务管理器beanName=transactionManager 如果需要设置请指定-->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <!-- 给切入点方法添加事务详情,name表示方法名称,*表示任意方法名称,propagation用于设置传播行为,read-only表示隔离级别,是否只读 -->
            <tx:method name="find*" propagation="SUPPORTS" rollback-for="Exception" />
            <tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" read-only="false" />
        </tx:attributes>
    </tx:advice>
	
    <!-- aop编写,让Spring自动对目标生成代理,需要使用AspectJ的表达式 -->
    <aop:config>
        <!-- 切入点 -->
        <aop:pointcut id="txPointCut" expression="execution(* com.wzy.mall.service.*.*(..))"/>
        <!-- 切面:将切入点与通知整合 -->
        <aop:advisor pointcut-ref="txPointCut" advice-ref="txAdvice" />
    </aop:config>

 

4、基于xml这种方式声明事务的原理分析

      我们使用了<tx:advice 来定义增强,然后再使用AOP来定位需要提供事务的连接点信息,然后再使用AOP技术来生成有事务特性的代理类来提供事务功能,接下来我们来看看诗选原理。

      4.1、tx 命名空间的解析TxNameSpaceHandler其源码如下:

public class TxNamespaceHandler extends NamespaceHandlerSupport {
    标签中用于指定事务管理器的参数名称用法<tx:advice id="txAdvice" transaction-manager="txManager">
    static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";

    默认的事务管理器名称
    static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";

    public TxNamespaceHandler() {
    }

    获取事务管理器的名称方法
    static String getTransactionManagerName(Element element) {
        return element.hasAttribute("transaction-manager") ? element.getAttribute("transaction-manager") : "transactionManager";
    }

    TxNamespaceHandler 的初始化方法,执行时机在解析xml期间,会先实例化TxNamespaceHandler实例,然后后使用实例来调用init()方法。
    public void init() {

        注册解析<tx:advice 标签的TxAdviceBeanDefinitionParser
        this.registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());

        注册解析<tx:annotation-driven标签的基于注解声明事务功能的AnnotationDrivenBeanDefinitionParser
        this.registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());

        如果使用了全局事务就是用AnnotationDrivenBeanDefinitionParser来解析
        this.registerBeanDefinitionParser("jta-transaction-manager", new AnnotationDrivenBeanDefinitionParser());
    }
}

       4.2、我们目前是使用了<tx:advice 来定义了一个增强来声明事务的,因此我们关注的是TxAdviceBeanDefinitionParser,我们带着问题过去,既然<tx:advice 是声明一个增强,那么TxAdviceBeanDefinitionParser必定是注册一个类型为Advice的类到IOC容器中,接下来我们来验证。TxAdviceBeanDefinitionParser是一个BeanDefinition的解析器,我们主要看其parse()方法。

          我们先来看TxAdviceBeanDefinitionParser的类图:

                         

           我们要找的parse()方法在AbstractBeanDefinitionParser类中,其源码如下:

	@Override
	public final BeanDefinition parse(Element element, ParserContext parserContext) {
                解析元素element从而得到一个BeanDefinition实例,此方法是抽象方法在子类
                AbstractSingleBeanDefinitionParser中有实现,我们待会需要查看 
                AbstractSingleBeanDefinitionParser的parseInternal方法实现。
		AbstractBeanDefinition definition = parseInternal(element, parserContext);
		if (definition != null && !parserContext.isNested()) {
			try {
				String id = resolveId(element, definition, parserContext);
				if (!StringUtils.hasText(id)) {
					parserContext.getReaderContext().error(
							"Id is required for element '" + parserContext.getDelegate().getLocalName(element)
									+ "' when used as a top-level tag", element);
				}
				String[] aliases = null;
				if (shouldParseNameAsAliases()) {
					String name = element.getAttribute(NAME_ATTRIBUTE);
					if (StringUtils.hasLength(name)) {
						aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
					}
				}

                                使用上面解析到的BeanDefinition实例来构建一个BeanDefinitionHolder并注册到IOC容器中。
				BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
				registerBeanDefinition(holder, parserContext.getRegistry());
				if (shouldFireEvents()) {
					BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
					postProcessComponentDefinition(componentDefinition);
					parserContext.registerComponent(componentDefinition);
				}
			}
			catch (BeanDefinitionStoreException ex) {
				parserContext.getReaderContext().error(ex.getMessage(), element);
				return null;
			}
		}
		return definition;
	}

                  AbstractSingleBeanDefinitionParser的parseInternal方法实现如下:

@Override
	protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
        创建一个空的GenericBeanDefinition以及BeanDefinitionBuilder
		BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
		String parentName = getParentName(element);
		if (parentName != null) {
			builder.getRawBeanDefinition().setParentName(parentName);
		}
                获取一个beanClass类型,这个在TxAdviceBeanDefinitionParser中实现了,且返回是一个TransactionInterceptor.class
		Class<?> beanClass = getBeanClass(element);
		if (beanClass != null) {
			builder.getRawBeanDefinition().setBeanClass(beanClass);
		}
		else {
			String beanClassName = getBeanClassName(element);
			if (beanClassName != null) {
				builder.getRawBeanDefinition().setBeanClassName(beanClassName);
			}
		}
		builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
		if (parserContext.isNested()) {
			// Inner bean definition must receive same scope as containing bean.
			builder.setScope(parserContext.getContainingBeanDefinition().getScope());
		}
		if (parserContext.isDefaultLazyInit()) {
			// Default-lazy-init applies to custom bean definitions as well.
			builder.setLazyInit(true);
		}
                做解析在TransactionInterceptor中实现了doParse方法。
		doParse(element, parserContext, builder);
		return builder.getBeanDefinition();
	}

                   从AbstractSingleBeanDefinitionParser的parseInternal方法中我们知道是构建一个类型为TransactionInterceptor的BeanDefinition实例注册到IOC容器中。这个TransactionInterceptor其实就是Advice类型的增强,也就是提供事务的功能的增强。TransactionInterceptor的类图如下:

              

             从类图中我们可以看出TransactionInterceptor继承了抽象类TransactionAspectSupport,TransactionAspectSupport里面提供了事务功能,比如TransactionAspectSupport的invokeWithinTransaction使用事务包围执行某方法,还有比如管理事务管理器的方法determineTransactionManager,提交事务的方法commitTransactionAfterReturning、事务回滚的方法completeTransactionAfterThrowing等。。。

             TransactionAspectSupport的主要的成员属性有:

       使用ThreadLocal绑定当前线程中的事务信息类TransactionInfo,我们可以显示的使用其获取事务信息
       private static final ThreadLocal<TransactionAspectSupport.TransactionInfo> transactionInfoHolder = new NamedThreadLocal("Current aspect-driven transaction");

       事务管理器的名称
       private String transactionManagerBeanName;

       事务管理器的实例
       private PlatformTransactionManager transactionManager;

       事务资源类 也就是我们配置的<tx:attributes> 标签数据,在创建事务到时候需要获取书屋的一下属性都是通过这个transactionAttributeSource来获取,比如获取事务的隔离级别、是否只读、事务的传播机制等。
       private TransactionAttributeSource transactionAttributeSource;

       beanFactory 比如应用的上下文
       private BeanFactory beanFactory;

       事务管理器缓存
       private final ConcurrentMap<Object, PlatformTransactionManager> transactionManagerCache = new ConcurrentReferenceHashMap(4);

             既然知道的TransactionAspectSupport组要这些属性那么是在什么时候进行设置的呢?也就是说transactionManager、transactionAttributeSource属性是在什么时候进行设置的呢?我们查看TxAdviceBeanDefinitionParser的

    doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder)方法会有答案,其源码如下:

    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
        此处传过来的builder中的BeanDefinition的beanClass是TransactionInterceptor.class

        第一步给transactionManager属性添加一个引用,这个引用就是指定事务管理器,其实现就是让
        transactionManager是一个RuntimeBeanReference(beanName),在TransactionInterceptor类 
        做依赖注入的时候会先实例化+初始化beanName=transactionManager的bean然后赋值给 
        transactionManager这个属性。
        builder.addPropertyReference("transactionManager", TxNamespaceHandler.getTransactionManagerName(element));
        List<Element> txAttributes = DomUtils.getChildElementsByTagName(element, "attributes");
        if (txAttributes.size() > 1) {
            parserContext.getReaderContext().error("Element <attributes> is allowed at most once inside element <advice>", element);
        } else if (txAttributes.size() == 1) {
            我们只配置了一个<tx:attributes> 不能配置多个,这里有体现
            Element attributeSourceElement = (Element)txAttributes.get(0);
           
            解析<tx:attributes>标签生成一个类型为TransactionAttributeSource的
            NameMatchTransactionAttributeSource BeanDefinition实例并且将其注册到IOC容器中。
            RootBeanDefinition attributeSourceDefinition = this.parseAttributeSource(attributeSourceElement, parserContext);

            将transactionAttributeSource赋值为通过解析<tx:attributes>而得到的
            TransactionAttributeSource 的BeanDefinition实例,在TransactionInterceptor的 
            bean依赖注入的时候会先实例化——初始化类型为TransactionAttributeSource的实例,然后 
            赋值给TransactionInterceptor的transactionAttributeSource属性。
            builder.addPropertyValue("transactionAttributeSource", attributeSourceDefinition);
        } else {
            builder.addPropertyValue("transactionAttributeSource", new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"));
        }

    }

 

        4.3、总结    

              TxAdviceBeanDefinitionParser做的事情就是构建一个beanClass=TransactionInterceptor.class的BeanDefinition实例注册到IOC容器中。在构建的过程会设置TransactionInterceptor的transactionManager属性的引用(RuntimeBeanReference),其次还会解析<tx:attributes>属性生成一个类型是TransactionAttributeSource.class的BeanDefintion实例注册到IOC容器中,并且将其赋值给TransactionInterceptor的transactionAttributeSource属性。因此当IOC容在装载TransactionInterceptor的bean完成后,那么TransactionInterceptor类的bean的transactionManager、transactionAttributeSource属性就会完成依赖注入了。

 


5、装配好的TransactionInterceptor实例如何提供事务
      TransactionInterceptor既然实现了AOP联盟的MethodInterceptor接口,那就一定实现了invoke方法,因此我们的主要重点就是TransactionInterceptor类的public Object invoke(final MethodInvocation invocation) throws Throwable方法,其源码如下:

   public Object invoke(final MethodInvocation invocation) throws Throwable {
        Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;

        调用父类TransactionAspectSupport的使用事务执行目标方法。
        return this.invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
            public Object proceedWithInvocation() throws Throwable {
                return invocation.proceed();
            }
        });
    }

        TransactionAspectSupport的invokeWithinTransaction方法实现源码解析

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final TransactionAspectSupport.InvocationCallback invocation) throws Throwable {
        使用之前构建的TransactionAttributeSource获取事务属性资源
        final TransactionAttribute txAttr = this.getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
        获取事务管理器
        final PlatformTransactionManager tm = this.determineTransactionManager(txAttr);
        final String joinpointIdentification = this.methodIdentification(method, targetClass, txAttr);
        Object result;
        以我们比较熟悉的DataSourceTranscationManager举例,肯定是走else,请移步else
        if (txAttr != null && tm instanceof CallbackPreferringPlatformTransactionManager) {
            final TransactionAspectSupport.ThrowableHolder throwableHolder = new TransactionAspectSupport.ThrowableHolder();

            try {
                result = ((CallbackPreferringPlatformTransactionManager)tm).execute(txAttr, new TransactionCallback<Object>() {
                    public Object doInTransaction(TransactionStatus status) {
                        TransactionAspectSupport.TransactionInfo txInfo = TransactionAspectSupport.this.prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);

                        Object var4;
                        try {
                            Object var3 = invocation.proceedWithInvocation();
                            return var3;
                        } catch (Throwable var8) {
                            if (txAttr.rollbackOn(var8)) {
                                if (var8 instanceof RuntimeException) {
                                    throw (RuntimeException)var8;
                                }

                                throw new TransactionAspectSupport.ThrowableHolderException(var8);
                            }

                            throwableHolder.throwable = var8;
                            var4 = null;
                        } finally {
                            TransactionAspectSupport.this.cleanupTransactionInfo(txInfo);
                        }

                        return var4;
                    }
                });
                if (throwableHolder.throwable != null) {
                    throw throwableHolder.throwable;
                } else {
                    return result;
                }
            } catch (TransactionAspectSupport.ThrowableHolderException var18) {
                throw var18.getCause();
            } catch (TransactionSystemException var19) {
                if (throwableHolder.throwable != null) {
                    this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                    var19.initApplicationException(throwableHolder.throwable);
                }

                throw var19;
            } catch (Throwable var20) {
                if (throwableHolder.throwable != null) {
                    this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                }

                throw var20;
            }
        } else {
            如果必要就创建事务
            TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
            result = null;

            try {
                执行目标方法(就是我们的crud方法)
                result = invocation.proceedWithInvocation();
            } catch (Throwable var16) {
                如果目标方法执行异常,那就回滚事务
                this.completeTransactionAfterThrowing(txInfo, var16);
                throw var16;
            } finally {
                将当前线程绑定的TransactionInfo移除调并设置为之前的TransactionInfo实例,绑定的时机是在createTransactionIfNecessary里面实现
                this.cleanupTransactionInfo(txInfo);
            }

            如果目标方法执行ok 那就提交事务
            this.commitTransactionAfterReturning(txInfo);
            return result;
        }
    }

         createTransactionIfNecessary方法实现

    protected TransactionAspectSupport.TransactionInfo createTransactionIfNecessary(PlatformTransactionManager tm, 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) {
                使用事务管理器获取一个TransactionStatus实例,在
                 AbstractPlatformTransactionManager中会实现,下面我们会跟踪源码来解析原理。
                status = tm.getTransaction((TransactionDefinition)txAttr);
            } else if (this.logger.isDebugEnabled()) {
                this.logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured");
            }
        }
        准备事务信息TransactionInfo实例,在此处使用TransactionStatus实例构建一个TransactionInfo
        实例,然后绑定到当前线程,就是使用TransactionAspectSupport中的transactionInfoHolder类型
        是ThreadLocal。
        return this.prepareTransactionInfo(tm, (TransactionAttribute)txAttr, joinpointIdentification, status);
    }

             AbstractPlatformTransactionManager中的getTransaction(TransactionDefinition definition)方法源码:

public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {

        获取一个事务对象,这个是一个抽象方法,由具体的事务管理器实现,我们以DataSourceTransactionManager举例说明,DataSourceTransactionManager返回的是一个类型为 DataSourceTransactionManager.DataSourceTransactionObject的内部类实例。
        Object transaction = this.doGetTransaction();
        boolean debugEnabled = this.logger.isDebugEnabled();
        if (definition == null) {
            definition = new DefaultTransactionDefinition();
        }

        
        if (this.isExistingTransaction(transaction)) {
            如果当前目标方法已经在事务的环境中,那就执行存在事务的逻辑,比如根据事务的传播行为进行逻辑修改。
            return this.handleExistingTransaction((TransactionDefinition)definition, transaction, debugEnabled);
        } else if (((TransactionDefinition)definition).getTimeout() < -1) {
            如果事务的超时时间配置为小于-1 那就直接抛出异常。
            throw new InvalidTimeoutException("Invalid transaction timeout", ((TransactionDefinition)definition).getTimeout());
        } else if (((TransactionDefinition)definition).getPropagationBehavior() == 2) {
            如果事务的传播机制是2,也就是PROPAGATION_MANDATORY 必须在已经存在的事务中执行,走到这里说明肯定不是已经在事务中调用,那就直接抛出异常。
            throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");
        } else if (((TransactionDefinition)definition).getPropagationBehavior() != 0 && ((TransactionDefinition)definition).getPropagationBehavior() != 3 && ((TransactionDefinition)definition).getPropagationBehavior() != 6) {
            if (((TransactionDefinition)definition).getIsolationLevel() != -1 && this.logger.isWarnEnabled()) {
                this.logger.warn("Custom isolation level specified but no actual transaction initiated; isolation level will effectively be ignored: " + definition);
            }

            boolean newSynchronization = this.getTransactionSynchronization() == 0;
            return this.prepareTransactionStatus((TransactionDefinition)definition, (Object)null, true, newSynchronization, debugEnabled, (Object)null);
        } else {
            AbstractPlatformTransactionManager.SuspendedResourcesHolder suspendedResources = this.suspend((Object)null);
            if (debugEnabled) {
                this.logger.debug("Creating new transaction with name [" + ((TransactionDefinition)definition).getName() + "]: " + definition);
            }

            如果是默认的PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED
            try {
                boolean newSynchronization = this.getTransactionSynchronization() != 2;
                创建一个DefaultTransactionStatus 事务状态信息实例
                DefaultTransactionStatus status = this.newTransactionStatus((TransactionDefinition)definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);

                开始事务是个抽象方法,我们会以DataSourceTransactionManager进行举例说明
                this.doBegin(transaction, (TransactionDefinition)definition);

                使用事务同步器TransactionSynchronizationManager将当前的事务数据使用ThreadLocal进行绑定。
                this.prepareSynchronization(status, (TransactionDefinition)definition);
                return status;
            } catch (RuntimeException var7) {
                this.resume((Object)null, suspendedResources);
                throw var7;
            } catch (Error var8) {
                this.resume((Object)null, suspendedResources);
                throw var8;
            }
        }
    }

                 我们从上面的AbstractPlatformTransactionManager中的getTransaction(TransactionDefinition definition)方法中提及到了两个抽象方法一个是doGetTransaction()、另一个是doBegin(transaction, definition);

          我们使用DataSourceTranscationManager来进行举例

                 1、doGetTransaction()源码:

    protected Object doGetTransaction() {
        创建一个事务对象
        DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject();
        设置事务对象是否允许保存点,保存点是什么自行百度
        txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
        
        使用事务同步管理器TransactionSynchronizationManager中获取jdbc的连接信息,为什么此处需要去获取,例如在一个事务中执行多次db的操作,在第一次操作的时候会将获取到的连接使用TransactionSynchronizationManager事务管理同步器进行线程绑定,那么当同一个事务里面,第二次进行db操作那就可以使用之前与线程绑定的连接来复用,因此此处会先获取线程绑定的连接。当然如果是第一次db操作,这里获取到的就是null。那么第一次操作的的时候是如何让获取到数据库连接的呢?在doBegin方法中会有解析
        ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.dataSource);

        将获取到的数据库连接设置到事务对象中。
        txObject.setConnectionHolder(conHolder, false);
        return txObject;
    }

             2、doBegin(transaction, definition)源码:

protected void doBegin(Object transaction, TransactionDefinition definition) {
        DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)transaction;
        Connection con = null;

        try {
            if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
                如果当前事务对象是没有数据库连接的,或者数据库连接需要与事务同步,就使用数据源获取数据库连接。
                Connection newCon = this.dataSource.getConnection();
                if (this.logger.isDebugEnabled()) {
                    this.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);
            if (con.getAutoCommit()) {
                txObject.setMustRestoreAutoCommit(true);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
                }
                关闭连接的自动提交,保证多条sql可以在同一个事务一起提交,此处就是jdbc开启事务的核心代码
                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()) {
                通过事务同步管理器将当前连接绑定到当前线程的本地变量
                TransactionSynchronizationManager.bindResource(this.getDataSource(), txObject.getConnectionHolder());
            }

        } catch (Throwable var7) {
            if (txObject.isNewConnectionHolder()) {
                DataSourceUtils.releaseConnection(con, this.dataSource);
                txObject.setConnectionHolder((ConnectionHolder)null, false);
            }

            throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", var7);
        }
    }

       到此整个基于xml声明事务的使用以及原理分析结束。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

                 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值