Mybatis源码分析_struts源码

Mybatis源码分析_struts源码Mybatis提供了一个简单的逻辑分页类RowBounds,其原理类似于在内存中做了一个分页,不是数据库层面的分页,性能不算好,谨慎使用一.RowBounds源码分析1RowBounds源码:/***Copyright2009-2017theoriginalauthororauthors.**LicensedundertheApacheLicense,Version2.0(the”License”);*youmaynot.

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

Mybatis提供了一个简单的逻辑分页类RowBounds,其原理类似于在内存中做了一个分页,不是数据库层面的分页,性能不算好,谨慎使用

一. RowBounds源码分析

1 RowBounds源码:

/** * Copyright 2009-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
package org.apache.ibatis.session;

/** * @author Clinton Begin */
public class RowBounds { 
   

  public static final int NO_ROW_OFFSET = 0;
  public static final int NO_ROW_LIMIT = Integer.MAX_VALUE;
  public static final RowBounds DEFAULT = new RowBounds();

  private final int offset;
  private final 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;
  }

}

2 SqlSession类

  /** * Retrieve a list of mapped objects from the statement key and parameter, * within the specified row bounds. * @param <E> the returned list element type * @param statement Unique identifier matching the statement to use. * @param parameter A parameter object to pass to the statement. * @param rowBounds Bounds to limit object retrieval * @return List of mapped object */
  <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);

我们发现SqlSession类中有一个重载的函数SelectList,其第三个参数是RowBounds
如下这样使用实现分页功能:

 SqlSession session = sqlSessionFactory.openSession();
 Map<String, String> sqlMap = new HashMap<>();
 sqlMap.put("sql", "select * from test_data");
 List<Map> result = null;
 String method = "com.iscas.biz.mp.mapper.DynamicMapper.dynamicSelect";
 RowBounds rowBounds = new RowBounds(600000, 20);
 result = session.selectList(method, sqlMap, rowBounds);

3 查看DefaultSqlSession中selectList的实现

 @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { 
   
    try { 
   
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) { 
   
      throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
    } finally { 
   
      ErrorContext.instance().reset();
    }
  }

4 查看BaseExecutor中query的实现

@Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { 
   
    BoundSql boundSql = ms.getBoundSql(parameter);
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
  }

5 查看BaseExecutor中query重载实现

 @Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { 
   
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
    if (closed) { 
   
      throw new ExecutorException("Executor was closed.");
    }
    if (queryStack == 0 && ms.isFlushCacheRequired()) { 
   
      clearLocalCache();
    }
    List<E> list;
    try { 
   
      queryStack++;
      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
      if (list != null) { 
   
        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      } else { 
   
        list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
      }
    } finally { 
   
      queryStack--;
    }
    if (queryStack == 0) { 
   
      for (DeferredLoad deferredLoad : deferredLoads) { 
   
        deferredLoad.load();
      }
      // issue #601
      deferredLoads.clear();
      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { 
   
        // issue #482
        clearLocalCache();
      }
    }
    return list;
  }

6 查看BaseExecutor中queryFromDatabase实现

  private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { 
   
    List<E> list;
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try { 
   
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally { 
   
      localCache.removeObject(key);
    }
    localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) { 
   
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
  }

7 查看BaseExecutor中doQuery的实现

@Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      throws SQLException { 
   
    Statement stmt = null;
    try { 
   
      flushStatements();
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
      Connection connection = getConnection(ms.getStatementLog());
      stmt = handler.prepare(connection, transaction.getTimeout());
      handler.parameterize(stmt);
      return handler.query(stmt, resultHandler);
    } finally { 
   
      closeStatement(stmt);
    }
  }

8 查看Configuration中newStatementHandler的实现

  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { 
   
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }

9 查看RoutingStatementHandler的构造器

  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { 
   

    switch (ms.getStatementType()) { 
   
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }

  }

10 查看SimpleStatementHandler的构造器

public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { 
   
    super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
  }

11 查看BaseStatementHandler的构造器

protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { 
   
    this.configuration = mappedStatement.getConfiguration();
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;

    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();

    if (boundSql == null) { 
    // issue #435, get the key before calculating the statement
      generateKeys(parameterObject);
      boundSql = mappedStatement.getBoundSql(parameterObject);
    }

    this.boundSql = boundSql;

    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
  }

12 查看Configuration中newResultSetHandler的实现

  public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
      ResultHandler resultHandler, BoundSql boundSql) { 
   
    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
    resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
    return resultSetHandler;
  }

13 查看DefaultResultSetHandler构造器

  public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement, ParameterHandler parameterHandler, ResultHandler<?> resultHandler, BoundSql boundSql,
                                 RowBounds rowBounds) { 
   
    this.executor = executor;
    this.configuration = mappedStatement.getConfiguration();
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;
    this.parameterHandler = parameterHandler;
    this.boundSql = boundSql;
    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();
    this.reflectorFactory = configuration.getReflectorFactory();
    this.resultHandler = resultHandler;
  }

重点来了,DefaultResultSetHandler是JDBC结果集的处理类,此类中有如下代码:

private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException { 
   
    try { 
   
      if (parentMapping != null) { 
   
        handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
      } else { 
   
        if (resultHandler == null) { 
   
          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
          handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
          multipleResults.add(defaultResultHandler.getResultList());
        } else { 
   
          handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
        }
      }
    } finally { 
   
      // issue #228 (close resultsets)
      closeResultSet(rsw.getResultSet());
    }
  }
 //
  // HANDLE ROWS FOR SIMPLE RESULTMAP
  //

  public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { 
   
    if (resultMap.hasNestedResultMaps()) { 
   
      ensureNoRowBounds();
      checkResultHandler();
      handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    } else { 
   
      handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    }
  }
  private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
      throws SQLException { 
   
    DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
    ResultSet resultSet = rsw.getResultSet();
    skipRows(resultSet, rowBounds);
    while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) { 
   
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
      Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
      storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
    }
  }
    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 { 
   
      for (int i = 0; i < rowBounds.getOffset(); i++) { 
   
        if (!rs.next()) { 
   
          break;
        }
      }
    }
  }

其中skipRows是此种分页方式的灵魂,根据RowBounds中的offSet偏移量,使ResultSet的游标向下移动若干,便实现了逻辑分页。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/190789.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • php-面向对象

    php-面向对象

    2021年7月4日
    100
  • dropdownlist的属性

    dropdownlist的属性DropDownList控件的使用(方法,属性)(.net学习笔记一)(2006-10-1117:57:03)转载分类:.net学习笔记从来没有写学习笔记的习惯,为了自己能坚定的把.net学好,努力吧!在.net中,DropDownList和ListBox是最常用的两个LIST控件,我的学习笔记也从这里开始吧!一、DropDownList命名空间:S…

    2022年10月17日
    0
  • asp:DropDownList 的一些属性

    asp:DropDownList 的一些属性使用 BorderStyle 属性为Web服务器控件指定边框样式。 使用一个 BorderStyle 枚举值设置此属性。 下表列出了可能的值。边框样式说明NotSet不设置边框样式。None无边框Dotted虚线边框。

    2022年10月17日
    0
  • 软件测试流程及规范[通俗易懂]

    软件测试流程及规范[通俗易懂]注:非通用标准流程,仅为大家提供参考。目标制定完整且具体的测试路线和流程,为快速、高效和高质量的软件测试提供基础流程框架。最终目标是实现软件测试规范化、标准化。测试流程说明流程图需求分析需求分析由SA制定,要求细化每一个功能的细节,每一个按钮的位置以及边界范围,对于稍大或稍复杂需求要求建模。(1)测试需求是制订测试计划的基本依据,只有确定了的测试需求才能够为测试计划提供客观依据;(2)测

    2022年6月7日
    31
  • 网页显示400 bad request_1类错误拒绝无效假设

    网页显示400 bad request_1类错误拒绝无效假设在ajax请求后台数据时有时会报 HTTP400错误-请求无效(Badrequest);出现这个请求无效报错说明请求没有进入到后台服务里;原因:1)前端提交数据的字段名称或者是

    2022年8月1日
    5
  • 雅虎前端优化14准则

    雅虎前端优化14准则

    1.尽可能使用少的HTTP请求MakefewerHTTPrequests; 

      这个是很重要的一条,具体措施是使用Imagemaps 和InlineImages;合并CSS和脚本代码。比如对于ImageMaps 
    (服务器端)server-side 
    →http://…/navbar.cgi?127,1

    2022年7月15日
    13

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号