mybatis的使用及源码分析(八) mybatis的rowbounds分析
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的实现
@Overridepublic <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的实现
@Overridepublic <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重载实现
@Overridepublic <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 #601deferredLoads.clear();if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {// issue #482clearLocalCache();}}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的实现
@Overridepublic <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 statementgenerateKeys(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的游标向下移动若干,便实现了逻辑分页。
mybatis的使用及源码分析(八) mybatis的rowbounds分析相关推荐
- 源码通透-mybatis源码分析以及整合spring过程
源码通透-mybatis源码分析以及整合spring过程 mybatis源码分析版本:mybaits3 (3.5.0-SNAPSHOT) mybatis源码下载地址:https://github.co ...
- mybatis源码阅读(八) ---Interceptor了解一下
转载自 mybatis源码阅读(八) ---Interceptor了解一下 1 Intercetor MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用.默认情况下,MyBatis允许 ...
- jdk、spring、mybatis、线程的源码分析
基础篇 从为什么String=String谈到StringBuilder和StringBuffer Java语法糖1:可变长度参数以及foreach循环原理 Java语法糖2:自动装箱和自动拆箱 集合 ...
- Alian解读SpringBoot 2.6.0 源码(八):启动流程分析之刷新应用上下文(下)
目录 一.背景 1.1.刷新的整体调用流程 1.2.本文解读范围 二.初始化特定上下文子类中的其他特殊bean 2.1.初始化主体资源 2.2.创建web服务 三.检查监听器bean并注册它们 四.实 ...
- 分析开源项目源码,我们该如何入手分析?(授人以渔)
点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:牛人 20000 字的 Spring Cloud 总结,太硬核了~ 1 前言 本文接上篇文章跟大家聊聊我们为什么 ...
- delphi查看源码版本_[Mybatis]-IDEA导入Mybatis源码
该系列文章针对 Mybatis 3.5.1 版本 一.下载 Mybatis 源码 step1.下载 Mybatis-3.5.1 源码 Mybatis 源码仓库地址 下载版本信息如下: 下载后进行解压, ...
- 封装成jar包_通用源码阅读指导mybatis源码详解:io包
io包 io包即输入/输出包,负责完成 MyBatis中与输入/输出相关的操作. 说到输入/输出,首先想到的就是对磁盘文件的读写.在 MyBatis的工作中,与磁盘文件的交互主要是对 xml配置文件的 ...
- 【Mybatis+spring整合源码探秘】--- mybatis整合spring事务原理
文章目录 1 mybatis整合spring事务原理 1 mybatis整合spring事务原理 本篇文章不再对源码进行具体的解读了,仅仅做了下面一张图: 该图整理了spring+mybatis整合后 ...
- mybatis源码学习篇之——执行流程分析
前言 在正式学习mybatis框架源码之前,需要先弄懂几个问题?myabtis框架是什么?为什么需要mybatis框架?使用mybatis框架带来的好处是什么? 回答这几个问题之前,我们先来看一下,之 ...
最新文章
- dubbo被阿里放弃原因_中间件小姐姐直播“带货”——阿里程序员必知的插件
- rtems 4.11 RTC驱动 (arm, beagle)
- Asp.net中的时区
- php原生判断,JavaScript
- CVE-2014-6332学习笔记
- 黑龙江工程学院锐捷校园网连接路由器免认证
- linux 下录音软件,linux下录音软件Audacity[zt]
- yum源的三种安装配置方式,总有一款适合你
- 微调StyleGAN2模型
- 一个屌丝程序猿的人生(六十九)
- Windows下生成 MD5 文件校验和的方法
- 硬件篇——阻容一阶滤波电路
- 微信qq邮箱提醒 服务器繁忙,微信设置密码失败,QQ无法绑定,邮箱服务器繁忙...
- 零基础学习CANoe Panel(6)—— 开关/显示控件(Switch/Indicator)
- 什么是SAAS——软件即服务
- 学编程c语言高考能加分吗,学好编程,中高考都能加分,还能保送清华北大!...
- 华为机试题(Java)
- B014 - ADC0809数字电压表可切换量程
- linux如何切换php版本
- VSCode 官网,下载安装包太慢,将地址中的 az764295.vo.msecnd.net 更换为 vscode.cdn.azure.cn
热门文章
- u盘重装系统步骤win10系统重装教程
- 原型、原型链、原型链继承 理解
- S3C2440 (4.3寸)LCD驱动程序之层次分析(十六)
- 图像处理工具类、Bitmap处理、理解ThumbnailUtils
- MySQL自增主键一定是连续的吗
- 分布式系统设计_分布式系统的设计审查清单
- 计算机设置调整吃鸡,吃鸡在哪里设置调整画面啊 吃鸡整体画面优化方法
- php中tabindex,HTML TabIndex属性
- ios和android的录音格式
- 前端工程师怎么写后端?试试 koa.js + Apache APISIX 吧~