private void pagination(Invocation invocation, StatementHandler target) throws SQLException {
   final MetaObject metaStatementHandler = getMetaObject(target);
   final BoundSql boundSql = target.getBoundSql();
   Page<?> page = PAGE_THREAD_LOCAL.get();
   if (page == null) {
     page = findPageParameter(boundSql.getParameterObject());
   }
   // 如果传入的参数中有分页对象且sql语句中有select,才做分页处理
   String sql = boundSql.getSql().toLowerCase();
   if (sql.startsWith("select") && page != null) {
     // 采用物理分页后,就不需要mybatis的内存分页了,所以重置下面的两个参数
     metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET);
     metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT);
     // 设置分页对象里的总记录数和总页数
     Connection connection = (Connection) invocation.getArgs()[0];
     MappedStatement mappedStatement =
         (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
     if (page.isCountTotal()) {
       int recordsTotal = getTotalCount(sql, connection, mappedStatement, boundSql);
       page.setTotalNum(recordsTotal);
     }
     // 最后重写sql
     String pageSql = buildPageSql(sql, page);
     metaStatementHandler.setValue("delegate.boundSql.sql", pageSql);
   }
 }
  /**
   * 获取总记录数
   *
   * @param sql 原始sql语句
   * @param conn
   * @param ms
   * @param boundSql
   * @return
   * @throws SQLException
   */
  private int getTotalCount(String sql, Connection conn, MappedStatement ms, BoundSql boundSql)
      throws SQLException {
    int start = sql.indexOf("from");
    if (start == -1) {
      throw new RuntimeException("statement has no 'from' keyword");
    }
    int stop = sql.indexOf("order by");
    if (stop == -1) {
      stop = sql.length();
    }

    String countSql = "select count(0) " + sql.substring(start, stop);
    BoundSql countBoundSql =
        new BoundSql(
            ms.getConfiguration(),
            countSql,
            boundSql.getParameterMappings(),
            boundSql.getParameterObject());
    ParameterHandler parameterHandler =
        new DefaultParameterHandler(ms, boundSql.getParameterObject(), countBoundSql);
    PreparedStatement stmt = null;
    ResultSet rs = null;
    int count = 0;
    try {
      stmt = conn.prepareStatement(countSql);
      // 通过parameterHandler给PreparedStatement对象设置参数
      parameterHandler.setParameters(stmt);
      rs = stmt.executeQuery();
      if (rs.next()) {
        count = rs.getInt(1);
      }
    } finally {
      CloseableUtil.closeQuietly(rs);
      CloseableUtil.closeQuietly(stmt);
    }
    return count;
  }