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 ,那就直接取所有的了。