文档章节

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

Zero零_度
 Zero零_度
发布于 2015/04/08 14:32
字数 960
阅读 44
收藏 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零_度
粉丝 69
博文 1253
码字总数 256245
作品 0
程序员
私信 提问
spring,mybatis事务管理配置与@Transactional注解使用

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

北京-卫斯理
2015/07/30
0
1
Spring事务管理(基础概念)

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

u014231523
2017/02/19
0
0
Java程序员从笨鸟到菜鸟之(八十)细谈Spring(九)spring+hibernate声明式事务管理详解

声明式事务管理是spring对事务管理的最常用的方式,因为这种方式对代码的影响最小,因此也符合非侵入性的轻量级容器的概念。Spring的事务管理是通过AOP的方式来实现的,因为事务方面的代码与...

长平狐
2012/11/12
744
0
运用@Transactional,自己抛出异常时不会回滚的原因,经验之谈

查看spring API可知 http://www.kuqin.com/spring2.0doc/index.html 对EJB来说,默认的行为是EJB容器在遇到系统异常 (通常指运行时异常)时自动回滚当前事务。EJB CMT遇到应用异常 (例如,...

孙斐
2011/12/04
0
0
云数据库POLARDB优势解读系列文章之④——物理复制

本文作者 黄忠(AnySQL) 日志是数据库的重要组成部份,按顺序以增量的方式记录了数据库上所有的操作,日志模块的设计对于数据库的可靠性、稳定性和性能都非常重要。 可靠性方面,在有一个数...

乙休
11/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

No transaction aspect-managed TransactionStatus in scope

No transaction aspect-managed TransactionStatus in scope 如果当前事务操作的实现所在方法没有开启事务,就会报出这样的异常。 例如你在A方法调用B方法,B方法开启了事务,A方法没有开启事...

嘴角轻扬30
12分钟前
1
0
SpringBoot整合Redis Lettuce

最近在准备集成的基础框架使用Spring Boot2搭建,其中Redis的支持不仅仅是丰富了它的API,更是替换掉底层Jedis的依赖,取而代之换成了Lettuce(生菜) jedis跟lettuce的区别 Lettuce 和 Jedis ...

lemonLove
19分钟前
1
0
mysqldumpslow 慢查询日志分析工具

首先得配置my.cnf: #====================================================================================================================##=====================================......

吴伟祥
20分钟前
2
0
如何基于阿里云搭建适合初创企业的轻量级架构?

----基于阿里云搭建的适合初创企业的轻量级架构 前言 在项目的初期往往存在很多变数,业务逻辑时刻在变,而且还要保证快速及时,所以,一个灵活多变、快速部署、持续集成并可以适应多种情况的...

阿里云云栖社区
20分钟前
1
0
SpringBoot基础教程4-1-1 使用JdbcTemplate操作数据库及事务管理

1 概述 SpringBoot封装的JdbcTemplate,使用模板模式,去除JDBC繁琐的重复代码,并提供了基于注解的事务管理;下面详细介绍如何使用JdbcTemplate操作数据和事务管理。 2 添加依赖 <dependenc...

Mkeeper
27分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部