文档章节

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

Zero零_度
 Zero零_度
发布于 2015/04/08 14:32
字数 960
阅读 37
收藏 0

前言:
  如果大家使用过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( 
truethis );
            }
            notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_COMMITTED );
        }
        
catch (SQLException e) {
            log.error(
"JDBC commit failed", e);
            commitFailed 
= true;
            
if ( callback ) {
                jdbcContext.afterTransactionCompletion( 
falsethis );
            }
            notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_UNKNOWN );
            
throw new TransactionException("JDBC commit failed", e);
        }
        
finally {
            closeIfRequired();
        }
    }   


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


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

本文转载自:http://www.blogjava.net/xmatthew/archive/2010/05/06/320123.html?opt=admin

共有 人打赏支持
Zero零_度
粉丝 68
博文 1246
码字总数 252959
作品 0
程序员
spring,mybatis事务管理配置与@Transactional注解使用

概述 事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。 Spring Framework对事务管理提供了一致的抽象,其特点如下: 为不同的事务API提供一致的编程模型...

北京-卫斯理
2015/07/30
0
1
如果只提交一个查询,有必要用事务吗?

http://www.blogjava.net/terry-zj/archive/2005/12/06/22792.html http://forum.javaeye.com/viewtopic.php?t=1603 但是并没有得出明确的结论。先让我们看看事务的定义: 引用: Transaction......

晨曦之光
2012/03/09
0
0
Spring事务管理(基础概念)

一般我们说事务,都是用一个术语来描述事务:ACID。也就事务的四个特性:原子性(Atomic),一致性(Consistent),隔离性(Isolated),持久性(Durable). 原子性:事务是由一个或多个活动所组成...

u014231523
2017/02/19
0
0
【转】事务策略: 了解事务陷阱

前沿(笔者加):事务(Transaction)是每一个与数据库有关的系统开发与设计人员都会接触到的东西,在Java中,传统的直接使用JDBC的事务开始、提交、回滚的方式已经随着各种应用开发框架(尤...

晨曦之光
2012/03/09
0
0
分析 Spring 的编程式事务管理及声明式事务管理(转)

开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务。通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之。 先决条件...

君辰
2015/07/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

String ,  StringBuffer ,  StringBuilder的区别

String , StringBuffer , StringBuilder的区别 String 首先,String 是用来表示一个字符串常量的,它是一个不可变对象,意味着,一旦我们创建了某个字符串之后,就不能再改变它的值了,我们可...

tsmyk0715
49分钟前
2
0
区块链100讲:UTXO 和 Account 模型对比

在当前区块链世界中,主要有两种记录保存方式,UTXO 模式(Unspent Transaction Output) 和 Account 模式。Bitcoin 采用的是 UTXO 模型,Ethereum 采用的 Account 模型,同样 CITA 也采用了 ...

HiBlock
51分钟前
1
0
Vue中路由管理器Vue Router使用介绍(三)

一、路由定义添加动态参数定义 1.路由定义项,使用:xx 方式 定义动态参数 { path:'/user/:id/:name', name:'user', component:()=>import('./views/User.vue') ...

tianma3798
52分钟前
1
0
从ibdata文件恢复mysql数据

DROP TABLE 恢复【一】 Recover InnoDB dictionary Percona Data Recovery Tool 单表恢复

IT--小哥
55分钟前
1
0
常见设计模式UML图

常见设计模式UML图 本文主要总结常见的设计模式的UML图,方便查阅和思考。 创建型模式 简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式和单例模式,这五种设计模式主要处理对象的创建...

陶小陶
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部