1. 程式人生 > >對於Mybatis物理分頁個人理解

對於Mybatis物理分頁個人理解

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

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

RowBounds原始碼如下:

public class RowBounds {

  /* 預設offset是0**/
  public
static final int NO_ROW_OFFSET = 0; /* 預設Limit是int的最大值,因此它使用的是邏輯分頁**/ public static final int NO_ROW_LIMIT = Integer.MAX_VALUE; public static final RowBounds DEFAULT = new RowBounds(); private int offset; private int limit; public RowBounds() { this.offset = NO_ROW_OFFSET; this.limit = NO_ROW_LIMIT; } public
RowBounds(int offset, int limit) { this.offset = offset; this.limit = limit; } public int getOffset() { return offset; } public int getLimit() { return limit; } }

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

private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
      throws SQLException {
    DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
    //跳過RowBounds設定的offset值
    skipRows(rsw.getResultSet(), rowBounds);
    //判斷資料是否小於limit,如果小於limit的話就不斷的迴圈取值
    while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
      Object rowValue = getRowValue(rsw, discriminatedResultMap);
      storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
    }
  }
private boolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) throws SQLException {
    //判斷資料是否小於limit,小於返回true
    return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
  }
  //跳過不需要的行,應該就是rowbounds設定的limit和offset
  private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {
    if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
      if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {
        rs.absolute(rowBounds.getOffset());
      }
    } else {
      //跳過RowBounds中設定的offset條資料
      for (int i = 0; i < rowBounds.getOffset(); i++) {
        rs.next();
      }
    }
  }

總結:Mybatis的邏輯分頁比較簡單,簡單來說就是取出所有滿足條件的資料,然後捨棄掉前面offset條資料,然後再取剩下的資料的limit條