`
asunx
  • 浏览: 9179 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

IBatis的分页研究

 
阅读更多

 

摘自:

http://cpu.iteye.com/blog/311395

yangtingkun   Oracle分页查询语句

ibaits.jar OracleDialect.java

 

在看JPetStore的代码时,发现它的分页处理主要是通过返回PaginatedList对象来完成的。如:在CatalogService类中

public  PaginatedList getProductListByCategory(String categoryId)  { 
    return  productDao.getProductListByCategory(categoryId); 
  }  


分页是操作数据库型系统常遇到的问题。分页实现方法很多,但效率的差异就很大了。iBatis是通过什么方式来实现这个分页的了。查看它的实现部分: 
  
返回的PaginatedList实际上是个接口,实现这个接口的是PaginatedDataList类的对象,查看PaginatedDataList类发现,每次翻页的时候最后都会调用下面这段函数

private  List getList( int  idx,  int  localPageSize)  throws  SQLException  { 
    return  sqlMapExecutor.queryForList(statementName, parameterObject, (idx)  *  pageSize, localPageSize); 
  }  

由于

public   interface  SqlMapClient  extends  SqlMapExecutor, SqlMapTransactionManager  {……}  


所以实际的调用次序如下:

SqlMapClientImpl.queryForPaginatedList -> SqlMapSessionImpl.queryForPaginatedList 
 -> SqlMapExecutorDelegate.queryForPaginatedList -> GeneralStatement.executeQueryForList 
 -> GeneralStatment.executeQueryWithCallback -> GeneralStatment.executeQueryWithCallback 
 -> SqlExecutor.executeQuery -> SqlExecutor.handleMultipleResults() -> SqlExecutor.executeQuery -> handleResults 

分页处理的函数如下

private   void  handleResults(RequestScope request, ResultSet rs,  int  skipResults,  int maxResults, RowHandlerCallback callback)  throws  SQLException  { 
     try   { 
      request.setResultSet(rs); 
      ResultMap resultMap  =  request.getResultMap(); 
       if  (resultMap  !=   null )  { 
        //  Skip Results  
         if  (rs.getType()  !=  ResultSet.TYPE_FORWARD_ONLY)  { 
           if  (skipResults  >   0 )  { 
            rs.absolute(skipResults); 
          }  
        }   else   { 
           for  ( int  i  =   0 ; i  <  skipResults; i ++ )  { 
             if  ( ! rs.next())  { 
              return ; 
            }  
          }  
        }  
  
        //  Get Results  
        int  resultsFetched  =   0 ; 
         while  ((maxResults  ==  SqlExecutor.NO_MAXIMUM_RESULTS  ||  resultsFetched  <  maxResults)  && rs.next())  { 
          Object[] columnValues  =  resultMap.resolveSubMap(request, rs).getResults(request, rs); 
          callback.handleResultObject(request, columnValues, rs); 
          resultsFetched ++ ; 
        }  
      }  
    }   finally   { 
      request.setResultSet( null ); 
    }  
  }  


由 此可见,iBatis的分页主要依赖于jdbcdriver的如何实现以及是否支持rs.absolute(skipResults)。它并不是一个好的 分页方式。它先要取出所有的符合条件的记录存入ResultSet对象,然后用absolute方法进行定位,来实现分页。当记录数较大(比如十万条) 时,整体的查询速度将会变得很慢。 
所以分页还是要考虑采用直接操作sql语句来完成。当然小批量的可以采用iBatis的分页模式。一般分页的sql语句与数据库的具体实现有关

mysql: 
 select   *   from  A limit startRow,endRow 
oracle: 
 select  b. *   from  ( select  a. * ,rownum  as  linenum  from  ( select   *   from  A) a  where  rownum  <=  endRow) b where  linenum  >=  startRow 


Hibernate的Oracle分页采用的就是是拼凑RowNum的Sql语句来完成的。参考代码如下:

         public  String createOraclePagingSql(String sql,  int  pageIndex,  int  pageSize) { 
            int  m  =  pageIndex  *  pageSize; 
            int  n  =  m  +  pageSize; 
            return   " select * from ( select row_.*, rownum rownum_ from (  "   +  sql 
                    
+   "  ) row_ where rownum <=  "   +  n  
                    
+   " ) where rownum_ >  "   +  m;  
        }  

例如:我要查询 UserInfo 表中的第 11 - 20 条的数据
select * from (select row_.*, rownum rownum_ from (select * from UserInfo order by sort desc) row_ where rownum <= 20) where rownum_ > 10

 

select t2.* from (select t1.*,rownum rownum_ from userinfo t1 where rownum <= 20) t2 where t2.rownum_ > 10;

 

   其中最内层的查询 SELECT * FROM UserInfo 表示不进行翻页的原始查询语句。 ROWNUM <= 20 和 ROWNUM_ > 10控制分页查询的每页的范围。

      上面给出的这个分页查询语句,在大多数情况拥有较高的效率。分页的目的就是控制输出结果集大小,将结果尽快的返回。 在上面的分页查询语句中,这种考虑主要体现在 WHERE ROWNUM <= 20 这句上。

选择第 10 到2 0 条记录存在两种方法,一种是上面例子中展示的在查询的第二层通过 ROWNUM <= 20 来控制最大值,在查询的最外层控制最小值。而另一种方式是去掉查询第二层的 WHERE ROWNUM <= 20 语句,在查询的最外层控制分页的最小值和最大值。这是,查询语句如下:

SELECT * FROM 
(
SELECT A.*, ROWNUM 
ROWNUM_ 
FROM (SELECT * FROM TABLE_NAME) A 
)
WHERE 
ROWNUM_ BETWEEN 11 AND 20

       对比这两种写法,绝大多数的情况下,第一个查询的效率比第二个高得多。

 

 

这是由于 CBO 优化模式 下, Oracle 可以将外层的查询条件推到内层查询中,以提高内层查询的执行效率。对于第一个查询语句,第二层的查询条件 WHERE ROWNUM <= 20 就可以被 Oracle 推入到内层查询中,这样 Oracle 查询的结果一旦超过了 ROWNUM 限制条件,就终止查询将结果返回了。

 

而第二个查询语句,由于查询条件 BETWEEN 11 AND 20 是存在于查询的第三层,而 Oracle 无法将第三层的查询条件推到最内层(即使推到最内层也没有意义,因为最内层查询不知道 ROWNUM_ 代表什么)。因此,对于第二个查询语句, Oracle 最内层返回给中间层的是所有满足条件的数据,而中间层返回给最外层的也是所有数据。数据的过滤在最外层完成,显然这个效率要比第一个查询低得多。

四.关于ibatis自己提供的分页API

PaginatedList paginatedList=sqlMap.queryForPaginatedList(statementName, parameterObject, pageSize);

 

这个是基于内存的分页,就是已经把所有数据load到内存了,才实现的伪分页。不会减少load的负荷。

 

 

      综上所述,小批量(<2w)可以采用ibatis自带的分页类,大批量的还是直接操纵sql,当然也可以将这些sql自己进行封装,或在包中封装都可以。包封装的示例代码如下:
一个封装了分页功能的Oracle Package

create   or   replace  package body FMW_FY_HELPER  is 
 PROCEDURE  GET_DATA(pi_sql  in   varchar ,pi_whichpage  in   integer ,pi_rownum  in   integer ,
 po_cur_data out cur_DATA,po_allrownum out  integer ,pio_succeed  in  out  integer )
 as  
 v_cur_data cur_DATA;
 v_cur_temp cur_TEMP;
 v_temp  integer ;
 v_sql  varchar ( 5000 );
 v_temp1  integer ;
 v_temp2  integer ;
 begin 
 pio_succeed : =   1 ;
 v_sql : =   ' select count( '' a '' ) from (  '   ||  pi_sql  ||   ' ) ' ;
 execute  immediate v_sql  into  v_temp;

 po_allrownum: = ceil(v_temp / pi_rownum);

 v_sql : =   '' ;
 v_temp : = pi_whichpage * pi_rownum  +   1 ;
 v_temp1: = (pi_whichpage - 1 ) * pi_rownum  +   1 ;
 v_temp2: = pi_whichpage * pi_rownum;
 v_sql: =   ' select * from (select rownum as rn,t.* from ( '   ||  pi_sql  || ' ) t where rownum< '   ||  to_char(v_temp)  ||   ')  where rn between  '   ||  to_char(v_temp1)  ||   '  and  '   ||  to_char(v_temp2);
 open  v_cur_data  for  v_sql;
 if  v_cur_data  % notfound
 then 
 pio_succeed: =- 1 ;
 return ;
 end if ;
 po_cur_DATA : =  v_cur_data;
 end ;
分享到:
评论

相关推荐

    分页的源码

    在IT行业中,分页是数据库查询的一个重要特性,特别是在数据量庞大的情况下,它能帮助...在 chap_ibatis 压缩包中,可能包含了相关的Ibatis分页源码示例,你可以进一步研究其中的细节,加深对Ibatis分页机制的理解。

    IBATIS_IN_ACTION

    - **数据访问对象(DAO)模式**:深入研究iBATIS如何支持DAO模式,简化数据访问逻辑,实现业务逻辑与数据访问的分离。 - **扩展iBATIS**:学习如何自定义插件,扩展iBATIS的功能,满足特定的业务需求。 ### iBATIS...

    ibatis学习资料汇总

    深入研究iBatis源码有助于理解其内部工作原理,包括如何解析XML配置文件,如何执行SQL语句,以及如何进行结果映射。源码分析可以帮助开发者更好地定制和优化自己的应用。 六、iBatis实践项目 通过实践项目,可以...

    Ibatis 练习Demo和笔记

    7. **插件机制**:介绍如何编写和使用Ibatis的插件,如PageHelper分页插件。 8. **最佳实践**:提供在实际项目中使用Ibatis的建议,如合理规划Mapper接口,避免SQL注入等。 【IbatisStudy项目结构及内容】 在提供...

    ssh2+ibatis框架

    SSH2+IBATIS框架是Java开发中常用的一套企业级应用开发框架...开发者可以通过研究这个示例,了解各个组件如何协同工作,以及如何实现分页查询。这有助于快速搭建企业级的Java Web应用,并为后续的开发工作提供基础。

    基于iBATIS动态SQL的应用研究.pdf

    此外,iBATIS可以统一编码风格,减少开发成本,开发者可以更专注于业务逻辑的实现,而无需过多关注分页、连接池、主键生成等基础操作。 iBATIS对SQL的简单封装,类似于在JDBC之上增加了一个外壳,它简化了JDBC的...

    struts2+spring+ibatis

    描述中提到的“分页分的挺完美的”,这涉及到Struts2或iBatis中的分页实现。在Struts2中,可以通过拦截器或者自定义插件来实现分页功能,而在iBatis中,可以通过编写动态SQL来实现分页查询。描述还指出“但是删除有...

    ibatis-in-action

    - **分页查询**:讲解如何实现分页查询功能。 - **多表查询**:介绍处理多表联接查询的方法。 #### 2.5 事务管理 - **事务概念**:解释事务的基本原理及其在iBATIS中的应用。 - **配置方法**:指导如何配置iBATIS以...

    ibatis资料整理.zip

    10. **插件扩展**:Ibatis允许开发者创建自定义插件,如PageHelper分页插件,以实现特定功能或优化性能。 11. **最佳实践**:在实际应用中,应合理规划Mapper接口和XML文件,避免过度复杂的SQL,同时注意优化事务...

    iBATIS 3 试用手记三

    在压缩包文件"iBatisResearch"中,可能包含了作者对iBATIS 3的研究文档、示例代码或者测试用例,这些内容可以帮助读者更直观地了解和掌握iBATIS 3的使用方法。通过阅读和实践这些材料,可以进一步巩固理论知识,提升...

    iBATIS in Action

    为了满足更复杂的查询需求,iBATIS提供了一系列高级查询技术,如动态SQL、分页查询等。动态SQL允许开发者根据运行时条件动态生成SQL语句,极大地提高了SQL语句的灵活性和复用性。 **2.5 事务管理** iBATIS支持多种...

    酒店客房管理系统(毕业设计) struts + spring + ibaits2.0

    【酒店客房管理系统(毕业设计) struts + spring + ...对于初学者来说,这个项目提供了学习Java Web开发和企业级框架的实践经验,通过研究源代码和数据库设计,可以深入了解MVC模式、数据库交互以及业务逻辑的实现。

    基于ext的j2ee开发

    ### 基于Ext的JavaEE快速开发研究 #### 摘要 本文重点探讨了如何将Ext框架与JavaEE中的多个开源框架整合,形成一套从前端到后端的高效开发流程。首先介绍了Ext框架的基本特性和优势,然后讨论了Ext与Struts2的整合...

    夏昕.深入浅出Hibernate

    本书有丰富的附录部,在附录中讲述了Hibernate常用的映射配置,Hibernate工具、XDoclet模板配置以及Hibernate的益友iBatis用法,还以卡片的形式列出了本书中所用的工具及软件,附录最后一部分是“快速启动代码”,供...

    mybatis_study.zip

    9. **异常处理**:MyBatis 提供了统一的异常处理机制,如`org.apache.ibatis.exceptions.PersistenceException`,便于捕获和处理数据库操作中的错误。 10. **最佳实践**:在压缩包中,我们可能还能发现一些最佳实践...

    struts项目1:网上企业办公自动化

    通过对源码的分析,开发者可以了解如何使用Struts2的注解来定义Action,如何处理表单提交,如何实现分页和搜索功能,以及如何进行错误和异常处理。此外,通过查看数据库设计,还可以了解到如何优化数据模型以满足...

    基于 Java 语言的极速 WEB + ORM 框架.zip

    6. **插件化设计**:JFinal 采用插件化设计,开发者可以根据需求选择使用不同的插件,如上传插件、缓存插件、分页插件等,这些插件可以快速扩展功能,而不会影响核心代码。 7. **模板引擎支持**:JFinal 支持 ...

    SpringBoot整合Mybatis!!附带源码!!

    在Java中,我们可以定义一个接口,该接口继承自`org.apache.ibatis.annotations.Mapper`,并包含SQL查询方法。同时,为每个接口创建对应的XML映射文件,用于编写SQL语句和结果映射。Spring Boot会通过`...

    很符合应届毕业生的简历模板

    - **项目二**:员工信息录入系统,使用Struts框架,实现了信息录入、修改、验证等功能,进行了分页等开源项目的实践研究。 ### 自我评价与职业态度 自我评价部分反映了求职者的个人特质和职业态度,这在招聘过程中...

Global site tag (gtag.js) - Google Analytics