`

对IBatis分页的改进,使ibatis支持hibernate式的物理分页

阅读更多

 

      公司的大部分项目都开始使用IBatis作为O/R Mapping了,但是在使用的过程中也发现了很多不方便和存在争议的地方,其中一个不方便的地方就是分页,目前的处理方式都是在sqlMap中写针对特定数据库的物理分页Sql语句,对于oracle数据库都是在分页的sql语句里面加上三层嵌套的sql语句,想了很多办法,都没能很好的避免这个问题,无意间在javaeye上看到了《使ibatis支持hibernate式的物理分页》这篇文章,可点进去已经被删除了,幸好google了一下有很多人已经收藏了,这里转载一下,以便再找不到了.

 

转载地址:http://www.blogjava.net/libin2722/articles/192504.html

 

一直以来ibatis的分页都是通过滚动ResultSet实现的,应该算是逻辑分页吧。逻辑分页虽然能很干净地独立于特定数据库,但效率在多数情况下不及特定数据库支持的物理分页,而hibernate的分页则是直接组装sql,充分利用了特定数据库的分页机制,效率相对较高。本文讲述的就是如何在不重新编译ibatis源码的前提下,为ibatis引入hibernate式的物理分页机制。

基本思路就是找到ibatis执行sql的地方,截获sql并重新组装sql。通过分析ibatis源码知道,最终负责执行sql的类是 com.ibatis.sqlmap.engine.execution.SqlExecutor,此类没有实现任何接口,这多少有点遗憾,因为接口是相对稳定契约,非大的版本更新,接口一般是不会变的,而类就相对易变一些,所以这里的代码只能保证对当前版本(2.1.7)的ibatis有效。下面是 SqlExecutor执行查询的方法:

Java代码 
  1. /** 
  2.    * Long form of the method to execute a query 
  3.    * 
  4.    * @param request - the request scope 
  5.    * @param conn - the database connection 
  6.    * @param sql - the SQL statement to execute 
  7.    * @param parameters - the parameters for the statement 
  8.    * @param skipResults - the number of results to skip 
  9.    * @param maxResults - the maximum number of results to return 
  10.    * @param callback - the row handler for the query 
  11.    * 
  12.    * @throws SQLException - if the query fails 
  13.    */  
  14.   public void executeQuery(RequestScope request, Connection conn, String sql, Object[] parameters,  
  15.                            int skipResults, int maxResults, RowHandlerCallback callback)  
  16.       throws SQLException {  
  17.     ErrorContext errorContext = request.getErrorContext();  
  18.     errorContext.setActivity("executing query");  
  19.     errorContext.setObjectId(sql);  
  20.   
  21.     PreparedStatement ps = null;  
  22.     ResultSet rs = null;  
  23.   
  24.     try {  
  25.       errorContext.setMoreInfo("Check the SQL Statement (preparation failed).");  
  26.   
  27.       Integer rsType = request.getStatement().getResultSetType();  
  28.       if (rsType != null) {  
  29.         ps = conn.prepareStatement(sql, rsType.intValue(), ResultSet.CONCUR_READ_ONLY);  
  30.       } else {  
  31.         ps = conn.prepareStatement(sql);  
  32.       }  
  33.   
  34.       Integer fetchSize = request.getStatement().getFetchSize();  
  35.       if (fetchSize != null) {  
  36.         ps.setFetchSize(fetchSize.intValue());  
  37.       }  
  38.   
  39.       errorContext.setMoreInfo("Check the parameters (set parameters failed).");  
  40.       request.getParameterMap().setParameters(request, ps, parameters);  
  41.   
  42.       errorContext.setMoreInfo("Check the statement (query failed).");  
  43.   
  44.       ps.execute();  
  45.       rs = getFirstResultSet(ps);  
  46.   
  47.       if (rs != null) {  
  48.         errorContext.setMoreInfo("Check the results (failed to retrieve results).");  
  49.         handleResults(request, rs, skipResults, maxResults, callback);  
  50.       }  
  51.   
  52.       // clear out remaining results  
  53.       while (ps.getMoreResults());  
  54.   
  55.     } finally {  
  56.       try {  
  57.         closeResultSet(rs);  
  58.       } finally {  
  59.         closeStatement(ps);  
  60.       }  
  61.     }  
  62.   
  63.   }  

 

其中handleResults(request, rs, skipResults, maxResults, callback)一句用于处理分页,其实此时查询已经执行完毕,可以不必关心handleResults方法,但为清楚起见,下面来看看 handleResults的实现:

Java代码 
  1. private void handleResults(RequestScope request, ResultSet rs, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException {  
  2.     try {  
  3.       request.setResultSet(rs);  
  4.       ResultMap resultMap = request.getResultMap();  
  5.       if (resultMap != null) {  
  6.         // Skip Results  
  7.         if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {  
  8.           if (skipResults > 0) {  
  9.             rs.absolute(skipResults);  
  10.           }  
  11.         } else {  
  12.           for (int i = 0; i < skipResults; i++) {  
  13.             if (!rs.next()) {  
  14.               break;  
  15.             }  
  16.           }  
  17.         }  
  18.   
  19.         // Get Results  
  20.         int resultsFetched = 0;  
  21.         while ((maxResults == SqlExecutor.NO_MAXIMUM_RESULTS || resultsFetched < maxResults) && rs.next()) {  
  22.           Object[] columnValues = resultMap.resolveSubMap(request, rs).getResults(request, rs);  
  23.           callback.handleResultObject(request, columnValues, rs);  
  24.           resultsFetched++;  
  25.         }  
  26.       }  
  27.     } finally {  
  28.       request.setResultSet(null);  
  29.     }  
  30.   }  

 

此处优先使用的是ResultSet的absolute方法定位记录,是否支持absolute取决于具体数据库驱动,但一般当前版本的数据库都支持该方法,如果不支持则逐条跳过前面的记录。由此可以看出如果数据库支持absolute,则ibatis内置的分页策略与特定数据库的物理分页效率差距就在于物理分页查询与不分页查询在数据库中的执行效率的差距了。因为查询执行后读取数据前数据库并未把结果全部返回到内存,所以本身在存储占用上应该差距不大,如果都使用索引,估计执行速度也差不太多。

继续我们的话题。其实只要在executeQuery执行前组装sql,然后将其传给 executeQuery,并告诉handleResults我们不需要逻辑分页即可。拦截executeQuery可以采用aop动态实现,也可直接继承SqlExecutor覆盖executeQuery来静态地实现,相比之下后者要简单许多,而且由于SqlExecutor没有实现任何接口,比较易变,动态拦截反到增加了维护的工作量,所以我们下面来覆盖executeQuery:

Java代码 
  1. package com.aladdin.dao.ibatis.ext;  
  2.   
  3. import java.sql.Connection;  
  4. import java.sql.SQLException;  
  5.   
  6. import org.apache.commons.logging.Log;  
  7. import org.apache.commons.logging.LogFactory;  
  8.   
  9. import com.aladdin.dao.dialect.Dialect;  
  10. import com.ibatis.sqlmap.engine.execution.SqlExecutor;  
  11. import com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback;  
  12. import com.ibatis.sqlmap.engine.scope.RequestScope;  
  13.   
  14. public class LimitSqlExecutor extends SqlExecutor {  
  15.   
  16.     private static final Log logger = LogFactory.getLog(LimitSqlExecutor.class);  
  17.       
  18.     private Dialect dialect;  
  19.   
  20.     private boolean enableLimit = true;  
  21.   
  22.     public Dialect getDialect() {  
  23.         return dialect;  
  24.     }  
  25.   
  26.     color: #7f0055; font-weig
    分享到:
    评论

相关推荐

    对IBatis分页的改进,使ibatis支持hibernate式的物理分页.doc

    总之,通过以上方法,我们可以实现在不修改iBatis源码的前提下,让iBatis支持类似Hibernate的物理分页,提高查询效率,尤其在大数据量的场景下,这种优化尤为关键。不过,需要注意的是,不同的数据库系统对物理分页...

    spring-ibatis-ext-plugin.1.0.0 扩展ibaits原生SQL

    本文讲述的就是如何在不重新编译ibatis源码的前提下,为ibatis引入hibernate式的物理分页机制。 基本思路就是找到ibatis执行sql的地方,截获sql并重新组装sql。通过分析ibatis源码知道,最终负责执行sql的类是 ...

    ssh2+ibatis框架

    SSH2+IBATIS框架是Java开发中常用的一套企业级应用开发框架组合,它将Spring、Hibernate、Struts2和iBatis等组件融合在一起,以提高开发效率和实现松耦合。以下是对这些框架及其整合方式的详细说明: **Spring框架*...

    springMVC+spring+hibernate+jquery分页完整项目,完整代码

    本项目是一个基于SpringMVC、Spring、Hibernate和jQuery的完整分页应用,涵盖了后端服务、数据持久化、前端交互等多个重要技术领域。下面将详细解释这些技术及其在项目中的应用。 1. SpringMVC:SpringMVC是Spring...

    mysql,jdbc详解,与ibatis对比。批量查询,分页处理。

    ### MySQL、JDBC详解及与iBatis对比 ...通过对MySQL的基本操作、JDBC的工作原理以及iBatis与JDBC的对比分析,我们可以更全面地理解数据库编程的关键概念和技术要点。希望本文能够帮助开发者们更加熟练地掌握这些技能。

    Ibatis中文版教程

    除了基本的查询,iBatis还支持动态SQL、批量操作、分页等功能,这些都是在实际项目中非常实用的能力。例如,动态SQL允许开发者根据不同的条件构建SQL语句,而批量操作则可以提高数据处理的效率。 ### 四、总结 ...

    ibatis-2.3.4.zip

    Ibatis的核心理念是“SQL就是SQL”,它并不像Hibernate那样尝试完全对象化数据库,而是将数据访问逻辑保留在SQL语句中,通过XML配置文件或注解来绑定SQL与Java对象。这使得开发人员可以充分利用SQL的灵活性,同时...

    iBatis简明教程及快速入门

    - **配置简单**:最新的iBatis版本(例如2.0)改进了XML配置文件,使其更加直观易懂,即使是没有深入学习过iBatis的新手也能够快速理解配置文件的结构和意义。 #### 三、环境搭建与基本配置 1. **安装iBatis**:...

    详细介绍Ibatis的用法

    与其他数据库持久层框架如JDO、Hibernate相比,Ibatis的最大优势在于其简洁性和易学性。只需掌握JavaBean、XML和SQL的基础知识,开发者就能有效地利用Ibatis发挥出SQL的强大功能。 #### 安装与配置 - **JAR文件和...

    ibatisDemo.rar

    与Hibernate相比,Ibatis更注重SQL的自由度,适合对SQL有深度需求的项目。而Hibernate则以全自动化为特点,通过ORM机制简化了数据库操作,但在大数据量和复杂查询时可能效率较低。选择Ibatis还是Hibernate,取决于...

    spring mvc+ibatis+spring注解

    在Ibatis中,可以通过动态SQL来实现排序(ORDER BY)和分页(LIMIT 或 ROWNUM),而在控制器层,Spring MVC 可以处理请求参数,传递分页和排序条件到服务层,从而返回对应的查询结果。 "新增、修改、删除"是CRUD...

    分页的源码

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

    ibatis学习笔记.txt

    - 对于那些对性能有较高要求的应用场景,iBatis 的灵活性和可控性使其成为更好的选择。 **5.2 复杂查询** - 当应用中包含大量复杂的 SQL 查询时,iBatis 的手动 SQL 控制能够更好地满足需求。 **5.3 简单查询** - ...

    Ibatis视频下载

    Ibatis是由Apache软件基金会维护的一个开源项目,它的核心功能是将SQL语句与Java代码分离,提供灵活的数据访问层,使数据库操作更加简单、高效。 在视频教程中,你可能会学到以下关键知识点: 1. **Ibatis简介**:...

    IBATIS.pdf

    虽然与Hibernate相比,iBATIS可能在自动化程度和缓存管理上略显不足,但对于那些需要对SQL查询有精细化控制的应用场景,iBATIS无疑是更好的选择。开发者应根据项目的具体需求和团队的技术栈来决定采用哪种框架,以...

    iBatis条件查询

    iBatis是一个轻量级的Java持久层框架,它与Hibernate相比,更加灵活,适合于对数据库操作有自定义需求的项目。在本资源中,"iBatis条件查询"着重展示了如何根据业务需求定制SQL语句进行数据检索,尤其在不涉及复杂...

    abc.rar_ABC_ibatis

    此外,由于Hibernate的自动管理特性,对于某些特定的数据库优化操作,如分页查询、批处理更新等,可能不如iBatis那么直接和高效。 其次,iBatis的学习曲线相对较平缓,因为它允许开发者保留对SQL的直接控制。而...

    ibatis 开发指南.pdf

    8. 分页查询:iBatis支持通过设置参数实现分页查询,这对大数据量的展示非常有用。 9. 缓存机制:iBatis提供了本地缓存和二级缓存机制,可以有效减少数据库访问,提高系统性能。开发者可以根据需求选择启用并配置...

    利用Mybatis的动态SQL实现物理分页.pdf

    【标题】:“利用Mybatis的动态SQL实现物理分页” 【描述】:本文主要探讨了在实际项目中如何利用Mybatis的动态SQL功能来解决大数据量下的物理分页问题,以避免内存溢出。 【标签】:“SQL 数据库 数据处理 参考...

Global site tag (gtag.js) - Google Analytics