一 直以来ibatis的分页都是通过滚动ResultSet实现的,应该算是逻辑分页吧。逻辑分页虽然能很干净地独立于特定数据库,但效率在多数情况下不及 特定数据库支持的物理分页,而hibernate的分页则是直接组装sql,充分利用了特定数据库的分页机制,效率相对较高。本文讲述的就是如何在不重新 编译ibatis源码的前提下,为ibatis引入hibernate式的物理分页机制。
基本思路就是找到ibatis执行sql的地方, 截获sql并重新组装sql。通过分析ibatis源码知道,最终负责执行sql的类是 com.ibatis.sqlmap.engine.execution.SqlExecutor,此类没有实现任何接口,这多少有点遗憾,因为接口是相 对稳定契约,非大的版本更新,接口一般是不会变的,而类就相对易变一些,所以这里的代码只能保证对当前版本(2.1.7)的ibatis有效。下面是 SqlExecutor执行查询的方法:
/**
* Long form of the method to execute a query
*
* @param request - the request scope
* @param conn - the database connection
* @param sql - the SQL statement to execute
* @param parameters - the parameters for the statement
* @param skipResults - the number of results to skip
* @param maxResults - the maximum number of results to return
* @param callback - the row handler for the query
*
* @throws SQLException - if the query fails
*/
public void executeQuery(RequestScope request, Connection conn, String sql, Object[] parameters,
int skipResults, int maxResults, RowHandlerCallback callback)
throws SQLException {
ErrorContext errorContext = request.getErrorContext();
errorContext.setActivity("executing query");
errorContext.setObjectId(sql);
PreparedStatement ps = null;
ResultSet rs = null;
try {
errorContext.setMoreInfo("Check the SQL Statement (preparation failed).");
Integer rsType = request.getStatement().getResultSetType();
if (rsType != null) {
ps = conn.prepareStatement(sql, rsType.intValue(), ResultSet.CONCUR_READ_ONLY);
} else {
ps = conn.prepareStatement(sql);
}
Integer fetchSize = request.getStatement().getFetchSize();
if (fetchSize != null) {
ps.setFetchSize(fetchSize.intValue());
}
errorContext.setMoreInfo("Check the parameters (set parameters failed).");
request.getParameterMap().setParameters(request, ps, parameters);
errorContext.setMoreInfo("Check the statement (query failed).");
ps.execute();
rs = getFirstResultSet(ps);
if (rs != null) {
errorContext.setMoreInfo("Check the results (failed to retrieve results).");
handleResults(request, rs, skipResults, maxResults, callback);
}
// clear out remaining results
while (ps.getMoreResults());
} finally {
try {
closeResultSet(rs);
} finally {
closeStatement(ps);
}
}
}
其 中handleResults(request, rs, skipResults, maxResults, callback)一句用于处理分页,其实此时查询已经执行完毕,可以不必关心handleResults方法,但为清楚起见,下面来看看 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()) {
break;
}
}
}
// 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);
}
}
此 处优先使用的是ResultSet的absolute方法定位记录,是否支持absolute取决于具体数据库驱动,但一般当前版本的数据库都支持该方 法,如果不支持则逐条跳过前面的记录。由此可以看出如果数据库支持absolute,则ibatis内置的分页策略与特定数据库的物理分页效率差距就在于 物理分页查询与不分页查询在数据库中的执行效率的差距了。因为查询执行后读取数据前数据库并未把结果全部返回到内存,所以本身在存储占用上应该差距不大, 如果都使用索引,估计执行速度也差不太多。
分享到:
相关推荐
公司的大部分项目都开始使用IBatis作为O/R Mapping了,但是在使用的过程中也发现了很多不方便和存在...想了很多办法,都没能很好的避免这个问题,无意间在javaeye上看到了《使ibatis支持hibernate式的物理分页》这篇文章,
总之,通过以上方法,我们可以实现在不修改iBatis源码的前提下,让iBatis支持类似Hibernate的物理分页,提高查询效率,尤其在大数据量的场景下,这种优化尤为关键。不过,需要注意的是,不同的数据库系统对物理分页...
本文讲述的就是如何在不重新编译ibatis源码的前提下,为ibatis引入hibernate式的物理分页机制。 基本思路就是找到ibatis执行sql的地方,截获sql并重新组装sql。通过分析ibatis源码知道,最终负责执行sql的类是 ...
【标题】:“利用Mybatis的动态SQL实现物理分页” 【描述】:本文主要探讨了在实际项目中如何利用Mybatis的动态SQL功能来解决大数据量下的物理分页问题,以避免内存溢出。 【标签】:“SQL 数据库 数据处理 参考...
(5)在ibatis中,想做物理分页,你必须在写一个列表sql,还要写一个90%一样的总页数的sql,不仅如此,你还要在列表sql外包上一层分页sql代码,你不觉得麻烦吗?但Hitis,直接返回给你实际执行的sql和paramters数组,...
(5)在ibatis中,想做物理分页,你必须在写一个列表sql,还要写一个90%一样的总页数的sql,不仅如此,你还要在列表sql外包上一层分页sql代码,你不觉得麻烦吗?但Hitis,直接返回给你实际执行的sql和paramters数组,...
(5)在ibatis中,想做物理分页,你必须在写一个列表sql,还要写一个90%一样的总页数的sql,不仅如此,你还要在列表sql外包上一层分页sql代码,你不觉得麻烦吗?但Hitis,直接返回给你实际执行的sql和paramters数组,...
(5)在ibatis中,想做物理分页,你必须在写一个列表sql,还要写一个90%一样的总页数的sql,不仅如此,你还要在列表sql外包上一层分页sql代码,你不觉得麻烦吗?但Hitis,直接返回给你实际执行的sql和paramters数组,...
(5)在ibatis中,想做物理分页,你必须在写一个列表sql,还要写一个90%一样的总页数的sql,不仅如此,你还要在列表sql外包上一层分页sql代码,你不觉得麻烦吗?但Hitis,直接返回给你实际执行的sql和paramters数组,...
(5)在ibatis中,想做物理分页,你必须在写一个列表sql,还要写一个90%一样的总页数的sql,不仅如此,你还要在列表sql外包上一层分页sql代码,你不觉得麻烦吗?但Hitis,直接返回给你实际执行的sql和paramters数组,...
Hibernate、Ibatis、Jdbc三者的区别:Hibernate和Ibatis都是JDBC的封装框架,但Hibernate是全自动的ORM映射,而Ibatis是半自动的。 Hibernate的运行原理:Hibernate通过映射关系将Java对象和数据库表进行映射。 ...
以前曾经用过ibatis,这是mybatis的前身,当时在做项目时,感觉很不错,比hibernate灵活。性能也比hibernate好。而且也比较轻量级,因为当时在项目中,没来的及做很很多笔记。后来项目结束了,我也没写总结文档。已经...
##### Hibernate、Ibatis、Jdbc三者的区别 - **Hibernate**:全ORM框架,简化了数据持久化操作。 - **iBatis**(MyBatis):半ORM框架,需要手动编写SQL语句。 - **JDBC**:直接使用SQL语句进行数据库操作。 ##### ...
##### Hibernate、Ibatis、Jdbc三者的区别 - **Hibernate**:全ORM解决方案,自动管理对象的生命周期。 - **MyBatis (原Ibatis)**:半ORM框架,提供动态SQL支持。 - **JDBC**:直接与数据库交互,灵活性高但编码...