• Richfaces为何那么“慢”?


    接触Richfaces时,我正在学习Dorado(上海锐道软件公司的Web表现层组件)控件,两者相比,Dorado是轻量级的,Richfaces是重量级的,比起DoradoRichfaces更丰富、更强大、更灵活、更高知名度、更高质量、更具生命力、资源更多,而且还免费。

    我毅然决定学习Richfaces,它的表现也让我肯定自己的正确选择。当我在实际项目中使用Richfaces时,发现我的项目运行起来很慢,比起PHP,简直是差远了,同样的记录数,如果使用PHP,页面响应速度是毫秒级的,使用Richfaces的响应速度却是秒级的。我不由得开始怀疑Richfaces的效率,在网络上搜寻相关问题时,很多人都有同样的感受,都觉得Richfaces比较慢,究其原因,有一种普遍的认识是Richfaces为了实现Ajax效果会下载很多js脚本本文件,会影响速度。的确,当做一个简单的Richfaces页面时,真正的数据可能才几十K,但是浏览器却下载了近1M的数据。在使用Firebug跟踪请求页面时,注意到Ajax脚本文件下载一次后再次使用时不会从服务器下载,而是直接来自Firefox缓存,这样的话页面响应速度并不会收到影响,那么到底是哪里出现了问题呢?

    一次偶然,我用rich:dataTable标记时,在创建数据列表recordsList时,在循环中放置了System.out.println(),当进行页面操作时,控制台有大量输出,显示recordsList被重复创建,这些页面操作包括页面切换、通过a4j:commandLinka4j:commandLink、或刷新a4j区域,也就是说,每当进行这些页面操作时,recordsList都会不停的创建,即每次都对数据库进行了读取,更让人惊讶的时,每次都将表中全部的记录读取出来,即便页面只显示了几条数据。看来问题就出在这里,至于Richfaces的效率问题不会是我们程序效率的关键因素。

    下面我们做个实验,使用MySQL数据库,创建数据表Org,设置ID_orgNameorgDesc三个字段,填充30万条记录,每页显示10条记录,共30012页我们分别使用三种创建数据表的方法对读取这张表的记录。

    1 内存分页,managed-bean-scope=request

    页面效果

    Orgmanaged-bena-scope的属性设置成request 通过Firebug记录每次切换页面所耗时的时间。可以看到,每一次切换页面都耗时了4秒的时间。

    2 内存分页,managed-bean-scope=session

    Orgmanaged-bena-scope的属性设置成session,注意到除了第一次请求耗时4.55秒外,切换页面时平均耗时仅50毫秒。但是,实际项目中我们不能在session中存放过多数据,尤其是这样30万条记录,几乎是灾难。

    3 数据库分页方式,即每次仅读取需要的10条数据,managed-bean-scope=request

    页面效果

    Firebug记录如下,平均耗时400毫秒。

    在实际项目中,我们如果不知道Richfaces的这种特性,往往选择服务器内存分页方式,当记录数非常小的时候,不会感觉到对速度的影响,但数据量大,访问量也大的时候,即便我们已经充分考虑减少对页面的刷新,但是你还是会发现速度很慢。于是我们开始选择数据库分页的方式,也只能这么选择。

    选择了数据库分页,我们还应该考虑如果减少对recordsList的创建,以便减少对数据库的查询,如果加以处理,每当点击a4j:commandButtona4j:commandLink时,或是对a4j区域进行了刷新时,recordsList都会被创建,虽然此时仅仅读取了10条记录,但是在页面上并没有显示变化,所以连这10条记录的读取都是多余的。那么我们如何控制呢?我们可以在a4j:commandButtona4j:commandLink设置一行代码<f:param name="reload" value="false"/>,即设置reload参数,然后在mRecordsList()中判断这个参数,如果reload等于false,就退出函数。

    if(!reload){

             return;

    }

    思路是对的,但是你会注意到a4j:commandButtona4j:commandLinkaction没有执行,这是怎么回事呢?实践说明recordsList总是先于action执行,我猜测是如果recordsList没有正确返回,action就不会被执行。于是,修改代码如下,创建一个recordsList,记录条数一样即可,便于节省时间,只循环添加相当于pageSizerecordsList,运行代码,奇迹出现了,在不更新recordsList的情况下action也得到了执行。while(i<10),不会耗时1毫秒,这样做能显著节约时间。

    if(!reload){

             int size = 0;

             while(size < me.getPageSize()){

                       recordsList.add(new Org(size));

                       size++;

             }

             return ;

    }

    你也可能会想,为什么不是while(i<1),只创建一条记录,这样不是更好?在实践中,如果只创建一条记录,那么只有第一条记录中的a4j:commandButtona4j:commandLink有效。

    关于速度问题,还有以下因素

    数据库执行SQL效率

    我们还应该注意SQL语句的写法,例如排序,按照ID_排序比按照orgName快的不是一秒两秒的问题,这一点你可以在MySQL中测试一下,尤其是使用limitoffset关键字控制分页时。这里还不考虑对字段的搜索。筛选条件或语句写法都会影响页面影响速度。

    浏览器影响

    实践证明在使用Richfaces标记时,FirefoxIE要快的多,在IE6中尤其慢。

  • 相关阅读:
    25- 解决'python -m pip install --upgrade pip' 报错问题
    2018.4.28 基于java的聊天系统(带完善)
    2018.4.27 Java的Swing常用事件
    2018.4.26 Mac安装Redis5.0.3版本服务器
    2018.4.25 设计模式之策略者模式
    2018.4.24 设计模式之桥接模式
    2018.4.23 数据结构
    2018.4.22 深入理解Java的接口和抽象类
    2018.4.21 如何正确快速安装/卸载云服务器Centos7安装GUI图形化界面GNOME桌面环境
    2018.4.20 设计模式之组合模式
  • 原文地址:https://www.cnblogs.com/liuzhengdao/p/1953151.html
Copyright © 2020-2023  润新知