1. 程式人生 > >Mybatis 邏輯分頁原理解析rowbounds

Mybatis 邏輯分頁原理解析rowbounds

Mybatis提供了一個簡單的邏輯分頁使用類RowBounds(物理分頁當然就是我們在sql語句中指定limit和offset值),在DefaultSqlSession提供的某些查詢介面中我們可以看到RowBounds是作為引數用來進行分頁的,如下介面:

  1. public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds)  

RowBounds原始碼如下:
  1. publicclass RowBounds {  
  2.   /* 預設offset是0**/
  3.   publicstaticfinal
    int NO_ROW_OFFSET = 0;  
  4.   /* 預設Limit是int的最大值,因此它使用的是邏輯分頁**/
  5.   publicstaticfinalint NO_ROW_LIMIT = Integer.MAX_VALUE;  
  6.   publicstaticfinal RowBounds DEFAULT = new RowBounds();  
  7.   privateint offset;  
  8.   privateint limit;  
  9.   public RowBounds() {  
  10.     this.offset = NO_ROW_OFFSET;  
  11.     this.limit = NO_ROW_LIMIT;  
  12.   }  
  13.   public RowBounds(int offset, int limit) {  
  14.     this.offset = offset;  
  15.     this.limit = limit;  
  16.   }  
  17.   publicint getOffset() {  
  18.     return offset;  
  19.   }  
  20.   publicint getLimit() {  
  21.     return limit;  
  22.   }  
  23. }  
邏輯分頁的實現原理:

在DefaultResultSetHandler中,邏輯分頁會將所有的結果都查詢到,然後根據RowBounds中提供的offset和limit值來獲取最後的結果,DefaultResultSetHandler實現如下:

  1. privatevoid handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)  
  2.       throws SQLException {  
  3.     DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();  
  4.     //跳過RowBounds設定的offset值
  5.     skipRows(rsw.getResultSet(), rowBounds);  
  6.     //判斷資料是否小於limit,如果小於limit的話就不斷的迴圈取值
  7.     while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {  
  8.       ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);  
  9.       Object rowValue = getRowValue(rsw, discriminatedResultMap);  
  10.       storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());  
  11.     }  
  12.   }  
  13. privateboolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) throws SQLException {  
  14.     //判斷資料是否小於limit,小於返回true
  15.     return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();  
  16.   }  
  17.   //跳過不需要的行,應該就是rowbounds設定的limit和offset
  18.   privatevoid skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {  
  19.     if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {  
  20.       if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {  
  21.         rs.absolute(rowBounds.getOffset());  
  22.       }  
  23.     } else {  
  24.       //跳過RowBounds中設定的offset條資料
  25.       for (int i = 0; i < rowBounds.getOffset(); i++) {  
  26.         rs.next();  
  27.       }  
  28.     }  
  29.   }  
總結:Mybatis的邏輯分頁比較簡單,簡單來說就是取出所有滿足條件的資料,然後捨棄掉前面offset條資料,然後再取剩下的資料的limit條