源代码解读Spring只读事务与读写事务的性能的差别

前言:
  如果大家使用过Spring事务管理,会发现Spring提供的事务分为“只读”和“读写”事务两类。这不免就会疑问这两种事务会有什么不同?本文则通过对Spring和Hibernate源代码的剖析来找出这两种事务的区别。特别是运行性能方面的区别。
  解读的源代码版本为 Spring 2.5.6.SEC01 ,Hibernate 3.3.2.GA。

Spring对事务的支持也分编程式和声明式,本文以基于Annotation方式的声明式事务为例:
 
  Spring的配置如下:

<bean
        class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
        <property name="proxyTargetClass" value="true"></property>
    </bean>
    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="entityManager" />
        <property name="jpaProperties">
            <props>
            </props>
        </property>
    </bean>

<bean id="transactionManager"
        class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <bean id="transactionInterceptor"
        class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <property name="transactionManager" ref="transactionManager" />
        <property name="transactionAttributeSource">
            <bean
                class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource" />
        </property>
    </bean>
    <bean id="transactionAttributeSourceAdvisor"
        class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
        <property name="transactionInterceptor"    ref="transactionInterceptor" />
    </bean>

从配置中,可以看到事务的拦截,都由 TransactionInterceptor 类进行处理
下面是invoke方法的核心处理过程:

public Object invoke(final MethodInvocation invocation) throws Throwable {
        // Work out the target class: may be <code>null</code>.
        // The TransactionAttributeSource should be passed the target class
        // as well as the method, which may be from an interface.
        Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);

// If the transaction attribute is null, the method is non-transactional.
        final TransactionAttribute txAttr =
                getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);
        final String joinpointIdentification = methodIdentification(invocation.getMethod());

if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) {
            // Standard transaction demarcation with getTransaction and commit/rollback calls.
            TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointIdentification);
            Object retVal = null;
            try {
                // This is an around advice: Invoke the next interceptor in the chain.
                // This will normally result in a target object being invoked.
                retVal = invocation.proceed();
            }
            catch (Throwable ex) {
                // target invocation exception
                completeTransactionAfterThrowing(txInfo, ex);
                throw ex;
            }
            finally {
                cleanupTransactionInfo(txInfo);
            }
            //处理事务的操作
            commitTransactionAfterReturning(txInfo);
            return retVal;
        }
        .省略
    }

针对事务的操作,就是调用 commitTransactionAfterReturning 方法进行事务的处理。
该方法会调用AbstractPlatformTransactionManager类的commit和processCommit方法。processCommit方法是真正调用Hibernate事务处理的实现。

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
        try {
            boolean beforeCompletionInvoked = false;
            try {
                prepareForCommit(status);
                triggerBeforeCommit(status);
                triggerBeforeCompletion(status);
                beforeCompletionInvoked = true;
                boolean globalRollbackOnly = false;
                if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
                    globalRollbackOnly = status.isGlobalRollbackOnly();
                }
                if (status.hasSavepoint()) {
                    if (status.isDebug()) {
                        logger.debug("Releasing transaction savepoint");
                    }
                    status.releaseHeldSavepoint();
                }
                else if (status.isNewTransaction()) { //如果是一个新启的事务
                    if (status.isDebug()) {
                        logger.debug("Initiating transaction commit");
                    }//则进行事务的提交处理
                    doCommit(status);
                }
             代码省略
    }

doCommit 方法的调用 会触发 Hibernate的JDBCTransaction的commit方法调用

public void commit() throws HibernateException {
        if (!begun) {
            throw new TransactionException("Transaction not successfully started");
        }

log.debug("commit");
        //如果是只读事务,Spring会将transactionContext的 isFlushModeNever 设置为true
        if ( !transactionContext.isFlushModeNever() && callback ) {
          //刷新一级缓存中的持久对象,向数据库发送sql语句  
            transactionContext.managedFlush(); //if an exception occurs during flush, user must call rollback()
        }

notifyLocalSynchsBeforeTransactionCompletion();
        if ( callback ) {
            jdbcContext.beforeTransactionCompletion( this );
        }

try {
            commitAndResetAutoCommit();
            log.debug("committed JDBC Connection");
            committed = true;
            if ( callback ) {
                jdbcContext.afterTransactionCompletion( true, this );
            }
            notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_COMMITTED );
        }
        catch (SQLException e) {
            log.error("JDBC commit failed", e);
            commitFailed = true;
            if ( callback ) {
                jdbcContext.afterTransactionCompletion( false, this );
            }
            notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_UNKNOWN );
            throw new TransactionException("JDBC commit failed", e);
        }
        finally {
            closeIfRequired();
        }
    }

关键点已经在上面的注释中说明。
当事务被标识为只读事务时,Spring可以对某些可以针对只读事务进行优化的资源就可以执行相应的优化措施,上面Spring告之hibernate的session在只读事务模式下不用尝试检测和同步持久对象的状态的更新。

总结:
  如果在使用事务的情况下,所有操作都是读操作,那建议把事务设置成只读事务,或者事务的传播途径最好能设置为 supports (运行在当前的事务范围内,如果当前没有启动事务,那么就不在事务范围内运行)或者 not supports (不在事务范围内执行,如果当前启动了事务,那么挂起当前事务),这样不在事务下,就不会调用transactionContext.managedFlush(); 方法。
所有只读事务与读写事务的比较大的运行性能区别就是只读事务避免了Hibernate的检测和同步持久对象的状态的更新,提升了运行性能。

时间: 2024-11-08 21:03:59

源代码解读Spring只读事务与读写事务的性能的差别的相关文章

【Spring】16、注解事务 @Transactional

概述 事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性.Spring Framework对事务管理提供了一致的抽象,其特点如下: 为不同的事务API提供一致的编程模型,比如JTA(Java Transaction API), JDBC, Hibernate, JPA(Java Persistence API和JDO(Java Data Objects) 支持声明式事务管理,特别是基于注解的声明式事务管理,简单易用 提供比其他事务API如JTA更简单的编程式事务管理

Spring in action读书笔记-事务管理

在软件开发领域,全有全无的操作被称为事务 事务的四个特性(ACID): 原子性(Atomtic):事务是由一个或多个活动所组成的一个工作单元,要么全部发生,要么全部不发生. 一致性(Consistent):一旦事务完成,系统应确保它所建的业务处于一致的状态. 隔离性(Isolated):事务允许多个用户操作同样的数据,但不能相互影响. 持久性(Durable):事务的结果应该存到数据库或者其他形式的持久化存储中. spring对事务管理的支持: 编码式:允许用户在代码中精确定义事务的边界 声明式

Spring AOP应用场景之事务管理

1.事务执行的时候是在前面开启事务,后面关闭事务,结束事务有两种方式,一种是正常的提交事务,一种是出现问题回滚事务. spring事务默认只有在抛出unchecked Exception才会回滚 UncheckedException包括error和runtimeException派生出的所有子类 2.什么时候才用事务?对数据库的数据进行批量或连表操作时,为了保证数据的一致性和正确性,我们需要添加事务管理机制进行管理.当对数据库的数据进行操作失败时,事务管理可以很好保证所有的数据回滚到原来的数据,

Spring 框架基础(05):事务管理机制,和实现方式

本文源码:GitHub·点这里 || GitEE·点这里 一.Spring事务管理 1.基础描述 Spring事务管理的本质就是封装了数据库对事务支持的操作,使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交和回滚. Connection conn = DriverManager.getConnection(); try { // 自动提交设置为false conn.setAutoCommit(false); // 执行增删改查操作 // 当操作成功后

spring ----编程式事务和声明式事务

一. 事务 事务管理对于企业应用而言是非常重要的,事务的存在保证了用户的每一次操作都是可靠的,当用户操作出现异常时也不至于破坏了后台的数据.例如银行的自动取款机,万一你在转账的时候出现了异常,事务机制会保证你后台的数据还是出异常操作之前的数据,也就是是你出异常的这些操作失效. 事务就是一组由于逻辑上紧密关联而合并成一个整体(工作单元)的多个数据库操作,这些操作要么都执行,要么都不执行. 银行转账操作:开启事务,就是保证转账的操作要么都执行,要么都不执行. 如果在你的账户减去转账金额后出现异常,不

Spring 使用注解方式进行事务管理

使用步骤: 步骤一.在spring配置文件中引入<tx:>命名空间<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation

Spring基于ThreadLocal的“资源-事务”线程绑定设计的缘起

题目起的有些拗口了,简单说,这篇文章想要解释Spring为什么会选择使用ThreadLocal将资源和事务绑定到线程上,这背后有着什么样的起因和设计动机,通过分析帮助大家更清晰地认识Spring的线程绑定机制.本文原文链接:http://blog.csdn.net/bluishglc/article/details/7784502 转载请注明出处! “原始”的数据访问写法 访问任何带有事务特性的资源系统,像数据库,都有着相同的特点:首先你需要获得一个访问资源的“管道”,对于数据库来说,这个所谓的

【转】Spring 使用注解方式进行事务管理

Spring 使用注解方式进行事务管理 原文链接 http://www.cnblogs.com/younggun/archive/2013/07/16/3193800.html#top 使用步骤: 步骤一.在spring配置文件中引入<tx:>命名空间 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-i

Spring事务隔离级别与传播机制,spring+mybatis+atomikos实现分布式事务管理

本文转载于本人另一博客[http://blog.csdn.net/liaohaojian/article/details/68488150] 1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). 原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做: 一致性(Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是应该处于正确