文档章节

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

Zero零_度
 Zero零_度
发布于 2015/04/08 14:32
字数 960
阅读 34
收藏 0
点赞 0
评论 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的检测和同步持久对象的状态的更新,提升了运行性能。

© 著作权归作者所有

共有 人打赏支持
Zero零_度
粉丝 66
博文 734
码字总数 252800
作品 0
程序员
Spring事务管理(基础概念)

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

u014231523 ⋅ 2017/02/19 ⋅ 0

Spring 中常用的两种事务配置方式以及事务的传播性、隔离级别

一、注解式事务 1、注解式事务在平时的开发中使用的挺多,工作的两个公司中看到很多项目使用了这种方式,下面看看具体的配置demo。 2、事务配置实例 (1)、spring+mybatis 事务配置 (2)、...

哲别0 ⋅ 04/20 ⋅ 0

spring事务和jdbc事务

Spring事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行: 获取...

TonyStarkSir ⋅ 04/16 ⋅ 0

Spring 实践 -拾遗

标签: Java与设计模式 Junit集成 前面多次用到与,在测试类添加这两个注解,程序就会自动加载Spring配置并初始化Spring容器,方便Junit与Spring集成测试.使用这个功能需要在pom.xml中添加如下依...

hanqing280441589 ⋅ 2016/03/12 ⋅ 0

@Transaction必知必会

1. Spring事务的基本原理 事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编码式和声明式的两种方式。编程式事务指的是通过编码方式...

maskwang520 ⋅ 04/15 ⋅ 0

基于可靠消息方案的分布式事务(二):Java中的事务

前言:在上一篇文章 基于可靠消息方案的分布式事务:Lottor介绍 中介绍了常见的分布式事务的解决方案以及笔者基于可靠消息方案实现的分布式事务组件Lottor的原理,并展示了应用的控制台管理。...

aoho ⋅ 06/01 ⋅ 0

spring事物配置,声明式事务管理和基于@Transactional注解的使用

事物管理对于企业应用来说是至关重要的,好使出现异常情况,它也可以保证数据的一致性。 spring支持编程式事务管理和声明式事务管理两种方式。 编程式事务管理使用TransactionTemplate或者直...

ruanjun ⋅ 2016/12/10 ⋅ 0

spring,mybatis事务管理配置与@Transactional注解使用

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

北京-卫斯理 ⋅ 2015/07/30 ⋅ 1

运用@Transactional,自己抛出异常时不会回滚的原因,经验之谈

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

孙斐 ⋅ 2011/12/04 ⋅ 0

spring如何在只读事务中提交数据

现在有个需求,我现在要去查询一个对象,如果这个对象不存在在,就初始创建一个,但这个查询是只读事务,没办法提交。有什么解决方案? 一种方法就是将这个查询方法加读写事务,这个不是我希...

pnwazgx ⋅ 2015/04/26 ⋅ 3

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JavaScript零基础入门——(八)JavaScript的数组

JavaScript零基础入门——(八)JavaScript的数组 欢迎大家回到我们的JavaScript零基础入门,上一节课我们讲了有关JavaScript正则表达式的相关知识点,便于大家更好的对字符串进行处理。这一...

JandenMa ⋅ 52分钟前 ⋅ 0

sbt网络问题解决方案

转自:http://dblab.xmu.edu.cn/blog/maven-network-problem/ cd ~/.sbt/launchers/0.13.9unzip -q ./sbt-launch.jar 修改 vi sbt/sbt.boot.properties 增加一个oschina库地址: [reposit......

狐狸老侠 ⋅ 今天 ⋅ 0

大数据,必须掌握的10项顶级安全技术

我们看到越来越多的数据泄漏事故、勒索软件和其他类型的网络攻击,这使得安全成为一个热门话题。 去年,企业IT面临的威胁仍然处于非常高的水平,每天都会看到媒体报道大量数据泄漏事故和攻击...

p柯西 ⋅ 今天 ⋅ 0

Linux下安装配置Hadoop2.7.6

前提 安装jdk 下载 wget http://mirrors.hust.edu.cn/apache/hadoop/common/hadoop-2.7.6/hadoop-2.7.6.tar.gz 解压 配置 vim /etc/profile # 配置java环境变量 export JAVA_HOME=/opt/jdk1......

晨猫 ⋅ 今天 ⋅ 0

crontab工具介绍

crontab crontab 是一个用于设置周期性被执行的任务工具。 周期性执行的任务列表称为Cron Table crontab(选项)(参数) -e:编辑该用户的计时器设置; -l:列出该用户的计时器设置; -r:删除该...

Linux学习笔记 ⋅ 今天 ⋅ 0

深入Java多线程——Java内存模型深入(2)

5. final域的内存语义 5.1 final域的重排序规则 1.对于final域,编译器和处理器要遵守两个重排序规则: (1)在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用...

江左煤郎 ⋅ 今天 ⋅ 0

面试-正向代理和反向代理

面试-正向代理和反向代理 Nginx 是一个高性能的反向代理服务器,但同时也支持正向代理方式的配置。

秋日芒草 ⋅ 今天 ⋅ 0

Spring 依赖注入(DI)

1、Setter方法注入: 通过设置方法注入依赖。这种方法既简单又常用。 类中定义set()方法: public class HelloWorldOutput{ HelloWorld helloWorld; public void setHelloWorld...

霍淇滨 ⋅ 昨天 ⋅ 0

马氏距离与欧氏距离

马氏距离 马氏距离也可以定义为两个服从同一分布并且其协方差矩阵为Σ的随机变量之间的差异程度。 如果协方差矩阵为单位矩阵,那么马氏距离就简化为欧氏距离,如果协方差矩阵为对角阵,则其也...

漫步当下 ⋅ 昨天 ⋅ 0

聊聊spring cloud的RequestRateLimiterGatewayFilter

序 本文主要研究一下spring cloud的RequestRateLimiterGatewayFilter GatewayAutoConfiguration @Configuration@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMi......

go4it ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部