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的游标向下移动若干,便实现了逻辑分页。

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • ubuntu下使用pip卸载包时出现Cannot uninstall scipy

    ubuntu下使用pip卸载包时出现Cannot uninstall scipyubuntu系统下使用pipuninstallscipy命令卸载包时,遇到报错信息为:ERROR:Cannotuninstall‘scipy’.Itisadistutilsinstalledprojectandthuswecannotaccuratelydeterminewhichfilesbelongtoitwhichwouldleadtoonlyapartialuninstall.最终发现通过以下方式可以解决:在/根目录下搜索“scip

    2022年10月17日
  • caller callee c语言 函数调用_Java invoke

    caller callee c语言 函数调用_Java invoke1、什么是JVM?JVM本质上就是一个软件,是计算机硬件的一层软件抽象,在这之上才能够运行Java程序,JAVA在编译后会生成类似于汇编语言的JVM字节码,与C语言编译后产生的汇编语言不同的是,C编译成的汇编语言会直接在硬件上跑,但JAVA编译后生成的字节码是在J今天在遇到个问题,如何在callee中获取caller的信息?搜索了一下,java提供一种如下的方法:StackTraceElemen…

    2022年10月26日
  • Virtualenv介绍、基本使用及在Pycharm下配置环境[通俗易懂]

    Virtualenv介绍、基本使用及在Pycharm下配置环境[通俗易懂]Virtualenv是一个创建独立Python运行环境的工具,主要解决Python软件开发过程中版本和依赖性问题。本文对Virtualenv做了简单的介绍、如何建立虚拟环境以及如何在Pycharm下配置Virtualenv环境

  • 简单理解Binder机制的原理

    一、概述Android系统中,涉及到多进程间的通信底层都是依赖于BinderIPC机制。例如当进程A中的Activity要向进程B中的Service通信,这便需要依赖于BinderIPC。不仅于此,整个Android系统架构中,大量采用了Binder机制作为IPC(进程间通信)方案。当然也存在部分其他的IPC方式,如管道、SystemV、Socket等。那么Android为什么不使用这…

  • 再看包括、扩展和泛化、继承

    再看包括、扩展和泛化、继承

    2021年11月30日
  • 框架梳理|企业大数据管理之道「建议收藏」

    框架梳理|企业大数据管理之道「建议收藏」大数据管理——企业转型升级与竞争力重塑之道》一书,从大数据驱动决策、大数据优化管理、大数据智慧营销、大数据发现创新、大数据推动转型、大数据保障安全六个维度全面分析了大数据对传统企业的应用价值,提供可借鉴的案例和深度有格局的思考。本文主要讲述的就是对于这本书的个人看法。

发表回复

您的电子邮箱地址不会被公开。

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