mybatis源码解读:cursor包

1.游标的使用

在使用mybatis进行数据库查询时,经常会查询到大量的结果。游标可以解决处理大量数据时不是一次读入整个结果集,而是逐一读入和处理结果,这样可以减少对内存的占用。

在mybatis中使用游标进行查询非常简单,映射文件不需要任何的变动,只需要在映射接口中标明返回值类型是Cursor。

2.游标接口

cursor包中源码非常简单,只有一个cursor接口和默认的实现类DefaultCursor。

Cursor类接口继承了Closeable接口和Iterable接口。Closeable接口表明一个类是可以关闭的,调用close方法可以释放类对象持有的资源。Iterable接口表明一个类是可以迭代的, 这样可以对类对象使用for-each操作。

public interface Cursor<T> extends Closeable, Iterable<T> {

/**
* 游标是否开启
* @return 是否开启
*/
boolean isOpen();
/**
* 是否已经完成了所有遍历
* @return 是否完成了所有遍历
*/
boolean isConsumed();

/**
* 返回当前元素的索引
* @return 当前元素的索引
*/
int getCurrentIndex();
}

3.默认游标

DefaultCursor类是默认的游标,有3个内部类。

1.CursorStatus内部类非常简单,是一个表明游标状态的枚举类。

private enum CursorStatus {

CREATED, // 表征游标新创建,结果集尚未消费

OPEN, // 表征游标正在被使用中,结果集正在被消费

CLOSED, // 表征游标已经被关闭,但其中的结果集未被完全消费

CONSUMED // 表征游标已经被关闭,其中的结果集已经被完全消费
}

2.ObjectWrapperResultHandler类继承ResultHandler接口,是一个简单结果处理器。

private static class ObjectWrapperResultHandler<T> implements ResultHandler<T> {
private T result;
/**
* 从结果上下文中取出并处理结果
* @param context 结果上下文
*/
@Override
public void handleResult(ResultContext<? extends T> context) {
// 取出结果上下文中的一条结果
this.result = context.getResultObject();
// 关闭结果上下文
context.stop();
}
}

ObjectWrapperResultHandler内部类只是将结果上下文中的一条结果取出来放进自身的属性,并未做进一步处理。

3.CursorIterator内部类继承了Iterator接口,这是一个迭代器类,实现了判断是否存在下一个元素的hashNext方法和返回下一个元素的next方法。

private class CursorIterator implements Iterator<T> {
// 缓存下一个要返回的对象,在next操作中完成写入
T object;
// next方法中返回的对象的索引
int iteratorIndex = -1;
/**
* 判断是否还有下一个元素,如果有则顺便写入object中
* @return 是否还有下一个元素
*/
@Override
public boolean hasNext() {
// 如果object!=null,则显然有下一个对象,就是object本身
if (object == null) {
// 判断是否还能获取到新的,顺便放到object中
object = fetchNextUsingRowBound();
}
return object != null;
}
/**
* 返回下一个元素
* @return 下一个元素
*/
@Override
public T next() {
T next = object;
if (next == null) { // object中无对象
// 尝试去获取一个
next = fetchNextUsingRowBound();
}
if (next != null) {
// 此时,next中是这次要返回的对象。object要么本来为null,要么已经取到next中。故清空
object = null;
iteratorIndex++;
// 返回next中的对象
return next;
}
throw new NoSuchElementException();
}
/**
* 删除当前的元素。不允许该操作,故直接抛出异常
*/
@Override
public void remove() {
throw new UnsupportedOperationException("Cannot remove element from Cursor");
}
}