`
yangwn
  • 浏览: 75658 次
  • 性别: 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 开发指南(pdf)

    系统数据处理量巨大,性能要求极为苛刻,这往往意味着我们必须通过经过高 度优化的SQL 语句(或存储过程)才能达到系统性能设计指标。 面对这样的需求,再次举起Hibernate 大刀,却发现刀锋不再锐利,甚至...

    iBATIS技术教程PPT和代码.rar

    系统数据处理量巨大,性能要求极为苛刻,这往往意味着我们必须通过经过高度优化的SQL语句(或存储过程)才能达到系统性能设计指标。面对这样的需求,再次举起 Hibernate 大刀,却发现刀锋不再锐利,甚至无法使用,...

    ibatis 开发指南

    系统数据处理量巨大,性能要求极为苛刻,这往往意味着我们必须通过经过高 度优化的SQL语句(或存储过程)才能达到系统性能设计指标。 面对这样的需求,再次举起Hibernate 大刀,却发现刀锋不再锐利,甚至无法...

    JAVA高并发高性能高可用高扩展架构视频教程

    打造高效代码结构(java性能优化) 新版本通俗易懂_观察者模式递进时讲解 ibatis连接数据库 高并发之单(多)生产者消费者线程 高并发复用数据库链接技术详解之数据库连接池 类加载器的高级特性(自定义类加器实现加密...

    IBatisNet.DataMapper 之简单三层

    系统数据处理量巨大,性能要求极为苛刻,这往往意味着我们必须通过经过高度优化的SQL语句(或存储过程)才能达到系统性能设计指标。 2.iBATIS之于小型、简单系统:非常适用 iBATIS自己就很小并且简单 iBATIS不会对...

    IBatisNet完整项目源码(含数据库)

    系统数据处理量巨大,性能要求极为苛刻,这往往意味着我们必须通过经过高度优化的SQL语句(或存储过程)才能达到系统性能设计指标。 2.iBATIS之于小型、简单系统:非常适用 iBATIS自己就很小并且简单 iBATIS不会...

    JavaEE求职简历-姓名-JAVA开发工程师.docx

    3.项目后台管理系统使用Shiro实现登录验证和权限管理(超级管理员、管理员、产品编辑员),iBatis动态sql语句编写及性能优化实现快速维护数据功能,Drui作为数据源,SpringTest+JUnit简化DAO层数据访问测试、Ea

    【白雪红叶】JAVA学习技术栈梳理思维导图.xmind

    性能优化 分层优化 系统级别 中间件级别 JVM级别 代码级别 分段优化 前端 web应用 服务应用 资源池 数据库 大数据与nosql zookeeper hadoop hbase mongodb strom spark java语言 语言语法基础 ...

    JAVA中级书籍

    性能优化; 反射机制;多线程;IO/NIO; 网络编程;常用数据结构和相关算法。 2、对面向对象的软件开发思想有清晰的认识、熟悉掌握常用的设计模式;设计模式;单例模式;工厂模式;代理模式;模板方法模式;责任链...

    mybatis_day01.docx

    前身是ibatis。 相比于hibernatehibernate为全自动化,配置文件书写之后不需要书写sql语句,但是欠缺灵活,很多时候需要优化; mybatis为半自动化,需要自己书写sql语句,需要自己定义映射。增加了程序员的一些操作...

    通向架构师的道路

    (第二十天)万能框架spring(二)maven结合spring与ibatis (第二十一天)万能框架spring(三)之SSH (第二十二天)万能框架spring(四)使用struts2 (第二十三天)maven与ant的奇妙整合 (第二十四天)之Oracle性能...

    通向架构师的道路(第1-20天)

    最近在学习SSH框架,看到大牛的博文,感觉很有指导...(第二十天)万能框架spring(二)maven结合spring与ibatis 一共27天,感兴趣的朋友可以去http://blog.csdn.net/lifetragedy/article/category/1175320 查看原创文档

    深入分析Java Web技术内幕 修订版

    最后介绍了Java 服务端技术,主要包括Servlet、Session 与Cookie、Tomcat 与Jetty服务器、Spring 容器、iBatis 框架和Velocity 框架等原理介绍,并介绍了服务端的一些优化技术。 《深入分析Java Web技术内幕(修订版...

    最新Java面试题视频网盘,Java面试题84集、java面试专属及面试必问课程

    │ Java面试题56.ibatis和hibernate有什么不同.mp4 │ Java面试题57.hibernate对象状态及其转换.mp4 │ Java面试题58:hibernate的缓存.mp4 │ Java面试题59.webservice的使用场景.mp4 │ Java面试题60.Activiti的...

    阿里巴巴编码规范 基础技能认证 考题分析(考题+答案).docx

    关于MySQL性能优化的描述,下列哪些说法是正确的:ABCD A .主键查询优先于二级索引查询。 B .表连接有一定的代价,故表连接数量越少越好。 C .一般情况下,二级索引扫描优先于全表扫描。 D .可以使用通过...

    mysql 海量数据的存储和访问解决方案

    通过数据切分来提高网站性能,横向扩展数据层已经成为架构研发人员首选的方式。水平切分数据库,可以降低单台机器的负载,同时最大限度的降低了了宕机造成的损失。通过负载均衡策略,有效的降低了单台机器的访问负载...

    最新Java面试宝典pdf版

    64、说出ArrayList,Vector, LinkedList的存储性能和特性 46 65、去掉一个Vector集合中重复的元素 46 66、Collection 和 Collections的区别。 47 67、Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用...

    Java面试笔试资料大全

    64、说出ArrayList,Vector, LinkedList的存储性能和特性 46 65、去掉一个Vector集合中重复的元素 46 66、Collection 和 Collections的区别。 47 67、Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用...

    Java面试宝典2010版

    64、说出ArrayList,Vector, LinkedList的存储性能和特性 65、去掉一个Vector集合中重复的元素 66、Collection 和 Collections的区别。 67、Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是...

    jfinalpluginsjfinal-dreampie.zip

    https://github.com/Dreampie?tab=repositories 分割成多个独立的插件进行优化,可以看我的博客拆分优化情况 http://my.oschina.net/wangrenhui1990/blog demo:(Angularjs前端 jfinal-dreampie插件) ...

Global site tag (gtag.js) - Google Analytics