`
yangwn
  • 浏览: 77086 次
  • 性别: Icon_minigender_2
  • 来自: 大连
社区版块
存档分类
最新评论
  • icewubin: kimmking 写道icewubin 写道Dollyn 写道 ...
    Java
  • kimmking: icewubin 写道Dollyn 写道我十分怀疑最后一条,很 ...
    Java
  • beneo: 完全忽略了一個好的JVM的優化能力 難道java是C編譯器么 ...
    Java
  • icewubin: Dollyn 写道我十分怀疑最后一条,很多编译器都会自动做类似 ...
    Java
  • Dollyn: 我十分怀疑最后一条,很多编译器都会自动做类似优化吧(不知道JD ...
    Java

Ibatis 性能优化

阅读更多
最近测试发现个IBatis 有个比较严重的性能问题, 描述如下:

1. define a bean class
public class Bean {
    private int    id;
    private String desc;
    private long   price;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    public long getPrice() {
        return price;
    }
    public void setPrice(long price) {
        this.price = price;
    }
}

2. 如果在这个Bean定义中,存在一个属性没有 Getter方法  在运行过程中, IBatis 会表现为把 class Bean 确定成一个ComplexAccessPlan的对象。那么, IBatis对Bean对象填充SQL执行后的返回结果会造成比较严重的性能问题。 复杂对象填充Bean的结果在性能上表现比较差一点。 这个性能差异随着需要设置属性数量的增加, 性能成正比的下降。  目前我测试的结果是10个属性情况下影响大约 5-6%的执行时间, 如果属性增加到 84个(中文站的offer对象),他的性能会导致超过30%的下降。 具体的原因, 我会如下解释:


  com.ibatis.sqlmap.engine.accessplan.AccessPlanFactory Line 60

      if (bytecodeEnhancementEnabled) {
        try {
          plan = new EnhancedPropertyAccessPlan(clazz, propertyNames);
        } catch (Throwable t) {
          try {
            plan = new PropertyAccessPlan(clazz, propertyNames);
          } catch (Throwable t2) {
            plan = new ComplexAccessPlan(clazz, propertyNames);
          }
        }
      }

com.ibatis.common.beans.ClassInfo Line256
public Method getGetter(String propertyName) {
    Method method = (Method) getMethods.get(propertyName);
    if (method == null) {
      throw new ProbeException("There is no READABLE property named '" + propertyName + "' in class '" + className + "'");
    }
    return method;
  }

class EnhancedPropertyAccessPlan/PropertyAccessPlan  call com.ibatis.common.beans.ClassInfo.getGetter(String) that  cause an exception  when a bean have no Getter method, AccessPlan object choose ComplexAccessPlan.

3. 根据以上的代码, 我们还可以得出如下结论(这是我给IBATIS开发团队的邮件部分, 不翻译:)):
IBtatis automatic decide a simple bean that property have no Getter method to be  Complex type.  IBatis does not prompt any warning  enhancementEnable option will be skipped. I think these ibatis exception handling is not smooth.  and If user's bean loose some Getter method,  a common user does not know why  ibatis performance become bad.
    就是一个对象由于Getter方法的缺失, IBatis把这个对象的当做复杂对象, 从而, 导致enhancementEnable=true(bean对象字节增加功能, 有兴趣的同学可以看看CGLIB中BulkBean的使用)的定义失去了任何作用, 进一步导致IBATIS的性能下降。

针对我们发现的问题, 我们建议如下解决问题:
1. 任何被IBatis 使用的对象属性必须定义完整的Setter/Getter方法
2. 避免使用自定义类型的对象属性
3. 如果部分属性需要被适当处理后才能使用的, 比如表中有一个字段price, 但是我们需要使用的是Money对象, 请按如下方式使用。primitivePrice作为数据库使用的属性, price作为应用程序使用的属性。
    public class Bean {    
        private Money             price            = null;
        private long              primitivePrice;
        public Money getPrice() {
            if (price == null) {
                this.price = new Money(0, 0);
                this.price.setCent(primitivePrice);
            }
            return price;
        }
      
        public void setPrice(Money price) {
            if (price == null) {
                this.price = new Money(0, 0);
            } else {
                this.price = price;
            }
            this.primitivePrice = price.getCent();
        }
       
        public void setPrimitivePrice(long price) {
            this.primitivePrice = price;
        }
        public long getPrimitivePrice() {
            return this.primitivePrice ;
        }
    }
======================================================================
IBatis on Oracle的性能优化
我们先主要看2个参数
    1.defaultRowPrefetch of oracle
    2.enhancementEnabled  of IBatis
环境
    1. Java HotSpot(TM) Server VM (build 1.5.0_12-b04, mixed mode)
       Java HotSpot(TM) Server VM (build 1.6.0_05-b13, mixed mode)
    2. Intel(R) Core(TM)2 CPU         T7400  @ 2.16GHz    L2 4M 
    3. JVM OPTION -Xms512m -Xmx1024m -XX:PermSize=96m
从数据库中读取10000行, 5列数据情况, Java Bean对象大约不到100个属性。循环20次, 外加5次的赃数据。
A.  defaultRowPrefetch=default enhancementEnabled=false/true     754ms/743ms
B.  defaultRowPrefetch=50      enhancementEnabled=false/true     389ms/382ms
C.  defaultRowPrefetch=100     enhancementEnabled=false/true     319ms/319ms
D.  defaultRowPrefetch=200     enhancementEnabled=false/true     277ms/274ms
E.  defaultRowPrefetch=500     enhancementEnabled=false/true     251ms/250ms
F.  defaultRowPrefetch=1000    enhancementEnabled=false/true     242ms/238ms
G.  defaultRowPrefetch=1000    enhancementEnabled=true           237ms(JAVA6)
H.  defaultRowPrefetch=200     enhancementEnabled=true           271MS(JAVA6)

总结以上情况, 在数据行比较多的情况下, defaultRowPrefetch值的提高, 对于性能的影响是显著的, 但是, 这个提升是牺牲很多内存为代价的, 因此, 如果过高的defaultRowPrefetch值会导致内存比较紧张。 另外值得说明的是, 在一样的参数前提下, JAVA6对于性能还是有一定的提升的。对于比较大的查询, defaultRowPrefetch经验值应该是200还是合理的。 另外, 对于enhancementEnabled选项带来的收益, 相对来说比较少。 但是,对于高压力的系统, 这是无IO等待下情况的代码执行提高这些是非常值。

以上的测试数据列数比较少, 因此在JAVA BEAN的建立上是非常的节约时间的, 我们看看在差不多100个属性的填充下的性能表现, 我们已经知道了defaultRowPrefetch带来收益的经验值。 因此, 我们设置defaultRowPrefetch=200.
A.  defaultRowPrefetch=200     enhancementEnabled=false     1736ms
B.  defaultRowPrefetch=200     enhancementEnabled=true      1721ms
C.  defaultRowPrefetch=50      enhancementEnabled=true       1866ms

OK, enhancementEnabled继续表明对性能的提升作用很小, 但是列的数据大小对性能的影响是非常大的。 但是, 我们无法确定这个时间是消耗在Java Bean 填充上 还是列读取上。IBatis没有具体的办法测试。 不过, 在减少结果参数说明的情况下, 性能能得到明显的提升, 我们还是可以断定, JAVA BEAN的被声明成结果映射的时候, 尽量减少结果映射的列,可以获得很高性能的提升。 因此, 使用IBatis操作大量的数据的表, 建议只映射应该获取到的数据, 而不是全部的列。 select * from db where... 你可以取需要的列到java bean. 总而言之:  select * from db where... 这样的形式对性能影响比  把所有的列映射到Java Bean 来的小!  set bean property + ResultSet.getXXX(int index)的操作消耗了大部分的性能。


一些代码片段:
       数据原的定义
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        <property name="driverClass">
            <value>oracle.jdbc.OracleDriver</value>
        </property>
        <property name="jdbcUrl">
            <value>jdbc:oracle:thin:@10.0.0.1:1521:test</value>
        </property>
        <property name="properties">
            <props>
                <prop key="user">test</prop>
                <prop key="password">test</prop>
                <prop key="defaultRowPrefetch">50</prop>
            </props>
        </property>
    </bean>
   
        为单个SQL查询定义defaultRowPrefetch, 在IBatis的定义中为fetchSize
    <select id="MS-FIND-PublishedOffers-By-MemberId-Paged" resultMap="RM-OfferResult" fetchSize="200">
   
    CGLIB增强定义
    <settings cacheModelsEnabled="true" enhancementEnabled="true" lazyLoadingEnabled="false" maxRequests="3000" maxSessions="3000" maxTransactions="3000" useStatementNamespaces="false"/>



分享到:
评论

相关推荐

    ibatis应对批量update

    6. **性能优化**: - 减少网络传输开销,尽可能减少与数据库服务器之间的交互次数。 - 合理设置批处理的大小,过大过小都会影响性能。 - 对于非常大的数据集,考虑分批次进行批量更新。 通过上述步骤,我们可以...

    ibatis教程,ibatis帮助文档

    3. 细粒度优化:iBATIS允许开发者进行更细致的SQL优化,例如针对特定场景编写高效的更新或查询语句。 4. 维护性:由于iBATIS的SQL存储在独立的XML文件中,相较于Hibernate在Java代码中混合SQL的情况,其可维护性更好...

    iBATIS3与JDBC性能对比

    总结来说,iBATIS3提供了更高的开发效率和易用性,而JDBC则在性能优化和灵活性上有优势。选择哪个取决于项目需求,例如,对于快速开发和维护的小型项目,iBATIS3可能是更好的选择;而对于性能要求极高,且需要深度...

    ibatis基础教学文档

    然而,这提供了更大的灵活性,特别是对于复杂或特定性能优化的SQL。 2. 细粒度优化:iBATIS允许对SQL进行更细致的优化,如直接指定更新单个字段的语句,或选择性地获取表的部分内容。 3. 可维护性:由于SQL保存在...

    ibatis api,ibatis文档,ibatis说明文档

    7. 执行性能:提供优化建议,如批处理、缓存使用等,以提升应用程序的运行效率。 总之,Ibatis是一个强大且灵活的Java持久层框架,其API、文档和说明文档为开发者提供了全面的工具和指导,帮助他们高效地进行数据库...

    ibatis系列 详细介绍

    8. **性能优化**:提供一些关于提高iBATIS性能的建议,如合理设计SQL、使用批处理等。 《ibatis.pdf》可能是iBATIS的官方文档或综合指南,可能包含更广泛的内容,如最佳实践、高级特性、与其他框架的集成等。 ...

    iBATIS-DAO-2.3.4.726.rar_com.ibatis.dao_iBATIS dao 2_iBatis DAO_

    通过阅读和理解源码,开发者不仅能掌握iBATIS DAO的基本使用,还能深入了解其内部实现,提升数据库操作的技巧和优化能力。同时,添加注释的过程也是深化理解的好方法,有助于在实际项目中更高效地应用iBATIS框架。

    ibatis拼接字符串

    2. **性能优化**:对于频繁执行的 SQL 语句,可以考虑缓存 SQL 语句或者使用其他性能优化措施。 3. **异常处理**:增加异常处理机制,确保程序的健壮性。 4. **代码复用**:封装常用的 SQL 动态构建逻辑,减少重复...

    ibatis_with_memcached

    总的来说,"ibatis_with_memcached"项目提供了一个实用的参考,展示了如何在实际开发中利用Ibatis与Memcached集成来优化数据访问,对于提升Java Web应用的性能具有很大的指导价值。开发者可以通过该项目学习到缓存...

    IBATIS_IN_ACTION

    - **性能优化与缓存**:了解如何利用iBATIS的缓存机制来提高应用性能,减少数据库访问次数。 - **数据访问对象(DAO)模式**:深入研究iBATIS如何支持DAO模式,简化数据访问逻辑,实现业务逻辑与数据访问的分离。 - ...

    ibatis

    7. 执行性能:尽管Ibatis 增加了一层间接,但因其轻量级特性,性能损失并不显著。而且,由于其灵活的SQL控制,可以在必要时进行优化,提高执行效率。 总结起来,Ibatis 是一个强大且灵活的持久层框架,它允许开发者...

    Hibernate性能优化研究.pdf

    ### Hibernate性能优化研究 #### 一、引言 随着企业级应用的发展,高效的数据持久化技术成为了提升系统性能的关键因素之一。Hibernate作为一种流行的面向Java环境的对象关系映射(Object-Relational Mapping,简称...

    IBatis .NET框架实例

    **八、性能优化** 通过合理的缓存策略、批处理和预编译SQL等手段,IBatis可以在不影响灵活性的同时提供良好的性能。 总结,IBatis .NET为.NET开发者提供了一种直观、灵活的方式来处理数据库操作。通过学习这个实例...

    ibatis2.3.4.rar

    总的来说,Ibatis 2.3.4的实例和jar包为你提供了一个学习和实践的平台,通过深入理解Ibatis的核心机制,你可以更好地设计和优化你的数据访问层,提升项目性能。在实践中不断探索,你会发现Ibatis是一个强大且灵活的...

    ibatis 开发指南 2004

    12. **最佳实践**:提供iBatis在实际项目中的应用建议,包括代码组织结构、性能优化、异常处理等方面。 13. **案例分析**:通过实际案例展示iBatis在不同场景下的应用,如CRUD操作、复杂查询、批量处理等。 14. **...

    ibatis课件

    这部分可能深入探讨了iBatis的一些高级特性,如存储过程的调用、多数据源支持、插件机制,或者是关于最佳实践和性能优化的内容。 学习iBatis的过程中,你需要理解以下关键知识点: 1. **基本概念**:了解iBatis是...

    ibatis源码

    2. **优化性能**:通过源码,可以找出可能的性能瓶颈,并针对性地进行优化。 3. **定制化开发**:对于有特殊需求的项目,可以直接在源码基础上进行二次开发,添加自定义功能。 4. **提升技能**:深入源码有助于...

    ibatis官方中文文档

    同时,这份教程可能还涵盖了异常处理、事务管理以及性能优化等相关内容。 **iBATIS存储过程调用** 在iBATIS中调用存储过程通常涉及以下几个步骤: 1. **配置存储过程**:在SQL映射文件中定义存储过程的标签,指定...

    ibatis笔记

    iBATIS 的设计理念是保持SQL与Java代码的分离,让开发者能够自由地编写SQL,从而在性能优化、复杂查询等方面具有更高的灵活性。 在iBATIS 3.2版本与2.3版本之间存在一些显著的变化。首先,iBATIS 3.2引入了更现代的...

    ibatis.Net

    6. **性能优化**:由于SQL语句是在运行时动态生成的,可以根据业务需求优化SQL,避免了大量硬编码SQL语句导致的性能问题。 7. **事务管理**:Ibatis.Net提供了对数据库事务的支持,你可以选择手动管理事务或者让...

Global site tag (gtag.js) - Google Analytics