From c6371e80eb362956a0cc5bebc6fb03e5b44416cb Mon Sep 17 00:00:00 2001 From: huifer Date: Thu, 26 Dec 2019 09:24:38 +0800 Subject: [PATCH] mybatis cursor --- .../Mybatis/核心处理层/Mybatis-Cursor.md | 337 ++++++++++++++++++ 1 file changed, 337 insertions(+) create mode 100644 docs/Mybatis/核心处理层/Mybatis-Cursor.md diff --git a/docs/Mybatis/核心处理层/Mybatis-Cursor.md b/docs/Mybatis/核心处理层/Mybatis-Cursor.md new file mode 100644 index 0000000..249d9b2 --- /dev/null +++ b/docs/Mybatis/核心处理层/Mybatis-Cursor.md @@ -0,0 +1,337 @@ +# Mybatis Cursor +- Author: [HuiFer](https://github.com/huifer) +- Description: 该文介绍 mybatis Cursor 源码 +## Cursor +- 源码位置:`org.apache.ibatis.cursor.Cursor` +- 继承`Iterable`说明是一个迭代器,继承`Closeable`说明有一个东西需要关闭 +```java +public interface Cursor extends Closeable, Iterable { + + /** + * 游标开始从数据库获取数据,返回true,反之false + * + * @return true if the cursor has started to fetch items from database. + */ + boolean isOpen(); + + /** + * 数据库元素都被获取,返回true,反之false + * + * @return true if the cursor is fully consumed and has returned all elements matching the query. + */ + boolean isConsumed(); + + /** + * 获取数据索引,从0开始,没有返回-1 + * Get the current item index. The first item has the index 0. + * + * @return -1 if the first cursor item has not been retrieved. The index of the current item retrieved. + */ + int getCurrentIndex(); +} +``` +## DefaultCursor +```java +public class DefaultCursor implements Cursor { + + /** + * 对象包装结果处理类 + */ + protected final ObjectWrapperResultHandler objectWrapperResultHandler = new ObjectWrapperResultHandler<>(); + // ResultSetHandler stuff + /** + * ResultSet 处理器 + */ + private final DefaultResultSetHandler resultSetHandler; + /** + * 结果映射 + */ + private final ResultMap resultMap; + /** + * ResultSet 包装对象 + */ + private final ResultSetWrapper rsw; + /** + * 分页的 + */ + private final RowBounds rowBounds; + /** + * 游标的迭代器 + */ + private final CursorIterator cursorIterator = new CursorIterator(); + + /** + * 游标开启判断 + */ + private boolean iteratorRetrieved; + + /** + * 游标状态,默认是创建未使用 + */ + private CursorStatus status = CursorStatus.CREATED; + /** + * 分页索引,默认-1 + */ + private int indexWithRowBound = -1; + + /** + * 构造方法 + * + * @param resultSetHandler + * @param resultMap + * @param rsw + * @param rowBounds + */ + public DefaultCursor(DefaultResultSetHandler resultSetHandler, ResultMap resultMap, ResultSetWrapper rsw, RowBounds rowBounds) { + this.resultSetHandler = resultSetHandler; + this.resultMap = resultMap; + this.rsw = rsw; + this.rowBounds = rowBounds; + } + + + @Override + public boolean isOpen() { + return status == CursorStatus.OPEN; + } + + @Override + public boolean isConsumed() { + return status == CursorStatus.CONSUMED; + } + + /** + * 当前索引 + * @return + */ + @Override + public int getCurrentIndex() { + return rowBounds.getOffset() + cursorIterator.iteratorIndex; + } + + /** + * 迭代器获取 + * @return + */ + @Override + public Iterator iterator() { + // 是否获取过 + if (iteratorRetrieved) { + throw new IllegalStateException("Cannot open more than one iterator on a Cursor"); + } + // 是否关闭 + if (isClosed()) { + throw new IllegalStateException("A Cursor is already closed."); + } + iteratorRetrieved = true; + return cursorIterator; + } + + /** + * {@link Closeable} 关闭{@link ResultSet} + */ + @Override + public void close() { + // 判断是否关闭 + if (isClosed()) { + return; + } + + ResultSet rs = rsw.getResultSet(); + try { + if (rs != null) { + rs.close(); + } + } catch (SQLException e) { + // ignore + } finally { + // 设置游标状态 + status = CursorStatus.CLOSED; + } + } + + /** + * 去到真正的数据行 + * @return + */ + protected T fetchNextUsingRowBound() { + T result = fetchNextObjectFromDatabase(); + while (objectWrapperResultHandler.fetched && indexWithRowBound < rowBounds.getOffset()) { + result = fetchNextObjectFromDatabase(); + } + return result; + } + + /** + * 从数据库获取数据 + * @return + */ + protected T fetchNextObjectFromDatabase() { + if (isClosed()) { + return null; + } + + try { + objectWrapperResultHandler.fetched = false; + // 游标状态设置 + status = CursorStatus.OPEN; + if (!rsw.getResultSet().isClosed()) { + // 处理数据结果放入,objectWrapperResultHandler + resultSetHandler.handleRowValues(rsw, resultMap, objectWrapperResultHandler, RowBounds.DEFAULT, null); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + + // 获取处理结果 + T next = objectWrapperResultHandler.result; + // 结果不为空 + if (objectWrapperResultHandler.fetched) { + // 索引+1 + indexWithRowBound++; + } + // No more object or limit reached + // 如果没有数据, 或者 当前读取条数= 偏移量+限额量 + if (!objectWrapperResultHandler.fetched || getReadItemsCount() == rowBounds.getOffset() + rowBounds.getLimit()) { + // 关闭游标 + close(); + status = CursorStatus.CONSUMED; + } + // 设置结果为null + objectWrapperResultHandler.result = null; + + return next; + } + + /** + * 是否关闭状态判断 + * + * @return + */ + private boolean isClosed() { + return status == CursorStatus.CLOSED || status == CursorStatus.CONSUMED; + } + + /** + * 下一个索引 + * @return + */ + private int getReadItemsCount() { + return indexWithRowBound + 1; + } + + /** + * 游标的状态 + */ + private enum CursorStatus { + + /** + * 新创建的游标, ResultSet 还没有使用过 + * A freshly created cursor, database ResultSet consuming has not started. + */ + CREATED, + /** + * 游标使用过, ResultSet 被使用 + * A cursor currently in use, database ResultSet consuming has started. + */ + OPEN, + /** + * 游标关闭, 可能没有被消费完全 + * A closed cursor, not fully consumed. + */ + CLOSED, + /** + * 游标彻底消费完毕, 关闭了 + * A fully consumed cursor, a consumed cursor is always closed. + */ + CONSUMED + } + + /** + * 对象处理结果的包装类 + * @param + */ + protected static class ObjectWrapperResultHandler implements ResultHandler { + + /** + * 数据结果 + */ + protected T result; + /** + * 是否null + */ + protected boolean fetched; + + /** + * 从{@link ResultContext} 获取结果对象 + * @param context + */ + @Override + public void handleResult(ResultContext context) { + this.result = context.getResultObject(); + context.stop(); + fetched = true; + } + } + + /** + * 游标迭代器 + */ + protected class CursorIterator implements Iterator { + + /** + * 下一个数据 + * Holder for the next object to be returned. + */ + T object; + + /** + * 下一个的索引 + * Index of objects returned using next(), and as such, visible to users. + */ + int iteratorIndex = -1; + + /** + * 是否有下一个值 + * @return + */ + @Override + public boolean hasNext() { + if (!objectWrapperResultHandler.fetched) { + object = fetchNextUsingRowBound(); + } + return objectWrapperResultHandler.fetched; + } + + /** + * 下一个值 + * @return + */ + @Override + public T next() { + // Fill next with object fetched from hasNext() + T next = object; + + if (!objectWrapperResultHandler.fetched) { + next = fetchNextUsingRowBound(); + } + + if (objectWrapperResultHandler.fetched) { + objectWrapperResultHandler.fetched = false; + object = null; + iteratorIndex++; + return next; + } + throw new NoSuchElementException(); + } + + /** + * 不可执行抛出异常 + */ + @Override + public void remove() { + throw new UnsupportedOperationException("Cannot remove element from Cursor"); + } + } +} +``` \ No newline at end of file