@Override
  public void select(
      final String statementName, final Object parameterObject, final ResultHandler handler) {
    if (isSqlAuditorBehaviorEnabled()) {
      getSqlAuditor()
          .audit(
              statementName,
              getSqlByStatementName(statementName, parameterObject),
              parameterObject);
    }
    if (isPartitioningBehaviorEnabled()) {
      SortedMap<String, DataSource> dsMap =
          lookupDataSourcesByRouter(statementName, parameterObject);
      if (dsMap != null && !dsMap.isEmpty()) {
        SqlSessionCallback action =
            new SqlSessionCallback() {
              @Override
              public Object doInSession(SqlSession sqlSession) {
                sqlSession.select(statementName, parameterObject, handler);
                return null;
              }
            };

        if (dsMap.size() == 1) {
          executeWith(dsMap.get(dsMap.firstKey()), action);
        } else {
          executeInConcurrency(action, dsMap);
        }
      }
    }
    super.select(statementName, parameterObject, handler);
  }
  @Override
  public <R> void executeQuery(
      String sqlNamespace,
      String queryName,
      Object parameterObj,
      int offset,
      int limit,
      ResultHandler<R> handler) {
    if (offset < 0 || offset == Integer.MAX_VALUE) {
      throw new IllegalArgumentException("Query result offset must be zero or greater.");
    }

    if (limit <= 0) {
      throw new IllegalArgumentException("Query results limit must be greater than zero.");
    }

    String query = makeQueryName(sqlNamespace, queryName);
    ResultHandlerTranslator<R> resultHandler = new ResultHandlerTranslator<R>(handler);
    try {
      if ((offset == 0) && (limit == Integer.MAX_VALUE)) {
        template.select(query, parameterObj, resultHandler);
      } else {
        RowBounds bounds = new RowBounds(offset, limit);
        template.select(query, parameterObj, bounds, resultHandler);
      }
    } catch (ClassCastException e) {
      throw new IllegalArgumentException("Return type of query does not match expected type.", e);
    } catch (Throwable e) {
      throw new QueryException(
          "Failed to execute query: \n"
              + "   Namespace: "
              + sqlNamespace
              + "\n"
              + "   queryName: "
              + queryName
              + "\n"
              + "   Parameter: "
              + parameterObj
              + "\n"
              + "   Offset:    "
              + offset
              + "\n"
              + "   Limit:     "
              + limit,
          e);
    }
  }