我们知道,Ibatis为我们提供了可以直接实现分页的方法
queryForList(String statementName, Object parameterObject, int skipResults, int maxResults)
参数:
statementName :要调用的statement
parameterObject: 参数对象
skipResults :要查询的起始记录 ((page.getPageNo()-1)*page.getPageSize())
maxResults: 返回的最大记录条数 (page.getPageSize())
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); } }
这个方法是翻阅ibatis源代码中找到的它实现分页查询的方法。
首先rs 是传过来的参数,rs在上级方法中是执行我们写的sql语句,将数据库中符合条件的所有数据查询出来得到的结果集
ResultSet.TYPE_FORWARD_ONLY是java.sql.ResultSet接口的方法,指的是数据库中的结果集只支持向前滚动。
rs.absolute(skipResults) 将游标移到相对第一行的指定行 为负数的话就是相对最后一行
下面的while就是取出我们最终要的分页结果放到某个对象中,返回给我们的查询方法。
通过分析源代码可知,ibatis分页有着很大的缺陷,首先将数据库中的所有数据取出来占用内存,其二采取游标滚动的方式取出我们所要的记录效率太低。我通过实际的例子测试,数据库中有300万条数据,每页显示10条,通过调用ibatis的分页方法和oracle 的sql两种方式实现分页查询。
结果表明,在前几页的查询两者效率相差不大,因为oracle的sql实现的分页也是将所有的数据查出来然后通过rownum属性取出我们所需要的。
越往后翻页ibatis分页的弱势(游标需要逐行滚动到2999990条)就越大,点击"尾页"链接进行查询后ibatis的分页查询已经比oracle sql的分页查询慢了5倍以上。
附 oracle sql分页的实现方法:
<sql id="pageStart"> <![CDATA[ select * from (select row_.*, rownum rownum_ from ( ]]> </sql> <sql id="pageEnd"> <![CDATA[ )row_ where rownum<=#end# ) where rownum_>=#start# ]]> </sql>
<!-- sql语句 --> <sql id="queryXsSql"> SELECT XS_ID, XS_NAME, XS.ZY_ID, XS_NUM, XS_SFZ, XS_TEL, XS_EMAIL, XS_ADDRESS, XS_DATE, XS_SEX, ZY.ZY_NAME, XY.XY_NAME FROM XS XS INNER JOIN ZY ZY ON XS.ZY_ID = ZY.ZY_ID INNER JOIN XY ON XY.XY_ID = ZY.XY_ID <dynamic prepend="where"> <isNotEmpty prepend="and" property="xs_name" > xs.xs_name like '%'||#xs_name#||'%' </isNotEmpty> <isNotEmpty prepend="and" property="xs_num" > xs.xs_num like '%'||#xs_num#||'%' </isNotEmpty> <isEqual prepend="and" property="xs_sex" compareValue="0" > xs.xs_sex='0' </isEqual> <isEqual prepend="and" property="xs_sex" compareValue="1" > xs.xs_sex='1' </isEqual> <isNotEmpty prepend="and" property="dateFrom" > <![CDATA[ to_date(xs.xs_date,'yyyy-MM-dd')>=to_date(#dateFrom#,'yyyy-MM-dd') ]]> </isNotEmpty> <isNotEmpty prepend="and" property="dateTo" > <![CDATA[ to_date(xs.xs_date,'yyyy-MM-dd')<=to_date(#dateTo#,'yyyy-MM-dd') ]]> </isNotEmpty> </dynamic> order by xs.xs_id desc </sql>
<select id="queryByOrclPage" parameterClass="com.bh.chc.manager.xs.XueShengPage" resultClass="xuesheng"> <include refid="pageStart"/> <include refid="queryXsSql"/> <include refid="pageEnd"/> </select> <select id="queryByOrclPageCount" resultClass="java.lang.Integer" parameterClass="com.bh.chc.manager.xs.XueShengPage"> select count(*) from ( <include refid="queryXsSql"/> ) </select>