sharding-jdbc系列之分页结果归并(九)

 

MergeEngine

public ResultSetMerger merge() throws SQLException {
          // 设置列的坐标信息
        selectStatement.setIndexForItems(columnLabelIndexMap);
          // 调用build()方法,build方法就是根据SQL条件,选择不同的结果合并器
        return decorate(build());
}
private ResultSetMerger decorate(final ResultSetMerger resultSetMerger) throws SQLException {
        ResultSetMerger result = resultSetMerger;
          // 是否需要分页
        if (null != selectStatement.getLimit()) {
              // 调用分页结果合并器处理
            result = new LimitDecoratorResultSetMerger(result, selectStatement.getLimit());
        }
        return result;
    }

上一文中,我们讲到了排序结果合并,通过new 出一个OrderByStreamResultSetMerger这个对象,创建一个排序的结果合并器, decorate的方法是在获取到

OrderByStreamResultSetMerger 这个对象之后需要执行的方法。 如果SQL的分页信息不为空,则会根据 原来的结果合并器和分页信息生成LimitDecoratorResultSetMerger 分页结果合并器。

举例说明

例:

select u.* from t_user u order by u.id limit 10000,10

上面这条SQL经过SQL路由改写,为取t_user表一万条往后面的10条,经过SQL路由,SQL改写,会生成如下SQL

dataSource1 ::: select u.* , u.id AS ORDER_BY_DERIVED_0 from t_user_00 u order by u.id limit 0,10010
dataSource2 ::: select u.* , u.id AS ORDER_BY_DERIVED_0 from t_user_00 u order by u.id limit 0,10010

细心的人已经发现,生成的SQL中limit已经变成0,10010 , 也就是要取前10010条出来,下面来看一下LimitDecoratorResultSetMerger 是怎么处理的。

LimitDecoratorResultSetMerger

public LimitDecoratorResultSetMerger(final ResultSetMerger resultSetMerger, final Limit limit) throws SQLException {
        super(resultSetMerger); // 设置 
        this.limit = limit; // 分页信息
        skipAll = skipOffset(); // 跳过offerSet
    }
private boolean skipOffset() throws SQLException {
          // 根据上面的例子,limit.getOffsetValue() 就是10000,
        for (int i = 0; i < limit.getOffsetValue(); i++) {
              // 直接将ResultSetMerger的结果游标往下翻
            if (!getResultSetMerger().next()) {
                  // 在控制游标往下翻的时候,返回false了,说明直接翻没了,表示结果里面没有合适的数据,直接返回true,skipAll = true
                return true;
            }
        }
          // SQL是否被重写过,改写过rowNumber则为0 ,否则则为offerSetValue
        rowNumber = limit.isRowCountRewriteFlag() ? 0 : limit.getOffsetValue();
        return false;
    }

步骤说明:

1.循环offersetValue,并且将resultSet的游标一直往下移动

2.判断getResultSetMerger().next()是否为false,如果是false,表示还未跳过offerset结果集里面的数据已经完了,

所以直接返回true,设置skipAll = true ,比如说我们上面的那个例子,取的是10000条后面的10条,那这里的offerset

就是10000,但是数据库只有9000条数据,因此在循环offerset的时候,9000条根本不够游标往下移10000次,因此最后返回

true, skipAll = true ,表示跳过了所有

3.判断SQL是否被改写过,默认为true,一般来说,都会被改写过。 改写过,则rowNumber = 0

next

@Override
    public boolean next() throws SQLException {
          // 第一步
        if (skipAll) {
              // skipAll = true 表示getResultSetMerger结果集在跳offerset的时候已经没了,
            return false;
        }
          // 第二步
        if (limit.getRowCountValue() > -1) {
              // 第三步
            return ++rowNumber <= limit.getRowCountValue() && getResultSetMerger().next();
        }
        // 第四步
        return getResultSetMerger().next();
    }

当mybatis调用结果next的时候,如果有分页,拿到的结果合并器就是LimitDecoratorResultSetMerger 这个,调用next方法判断结果集里面有没有

数据的时候,会直接调用到LimitDecoratorResultSetMerger 这个类的next方法

步骤说明:

1.skipAll = true 表示getResultSetMerger结果集在跳offerset的时候已经没了,直接返回false。

2.limit.getRowCountValue()表示你要取几条数据,limit 0,10 , 这个里面,rowCountValue = 10

3.rowNumber加1 ,然后看下是否小于等于rowCountValue ,如果OK,则调用getResultSetMerger的next的方法,这个地名就他分页功能实现

的地方了, 每次next之前,先对rowNumber加1 ,如果加完了1 还小于等于rowCountValue ,则说明还没有取够条数,则继续调用getResultSetMerger的next方法

4.这个地方就是防止有些人rowCountValue 写了小于-1的,如果小于-1 ,那就直接取所有的了。

猜你喜欢

转载自blog.csdn.net/u012394095/article/details/81625606