首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Mybatis源码分析_struts源码

Mybatis源码分析_struts源码

作者头像
全栈程序员站长
发布2022-11-08 19:56:29
发布2022-11-08 19:56:29
1.4K00
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

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

一. RowBounds源码分析

1 RowBounds源码:

代码语言:javascript
代码运行次数:0
运行
复制
/** * 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类

代码语言:javascript
代码运行次数:0
运行
复制
  /** * 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 如下这样使用实现分页功能:

代码语言:javascript
代码运行次数:0
运行
复制
 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的实现

代码语言:javascript
代码运行次数:0
运行
复制
 @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的实现

代码语言:javascript
代码运行次数:0
运行
复制
@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重载实现

代码语言:javascript
代码运行次数:0
运行
复制
 @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实现

代码语言:javascript
代码运行次数:0
运行
复制
  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的实现

代码语言:javascript
代码运行次数:0
运行
复制
@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的实现

代码语言:javascript
代码运行次数:0
运行
复制
  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的构造器

代码语言:javascript
代码运行次数:0
运行
复制
  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的构造器

代码语言:javascript
代码运行次数:0
运行
复制
public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { 

super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}

11 查看BaseStatementHandler的构造器

代码语言:javascript
代码运行次数:0
运行
复制
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的实现

代码语言:javascript
代码运行次数:0
运行
复制
  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构造器

代码语言:javascript
代码运行次数:0
运行
复制
  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结果集的处理类,此类中有如下代码:

代码语言:javascript
代码运行次数:0
运行
复制
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.cn/190789.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年9月22日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档