Result set merging of sharding-jdbc source code parsing

Result set merge source code analysis

 

Find this method, the method that executes the query

com.dangdang.ddframe.rdb.sharding.jdbc.core.statement.ShardingPreparedStatement#executeQuery

@Override
    public ResultSet executeQuery() throws SQLException {
        ResultSet result;
        try {
// route to the precompiled object execution unit collection
            Collection<PreparedStatementUnit> preparedStatementUnits = route();
// Multi-threaded execution of sql query returns a collection of result set objects
            List<ResultSet> resultSets = new PreparedStatementExecutor(
                    getShardingConnection().getShardingContext().getExecutorEngine(), getRouteResult().getSqlStatement().getType(), preparedStatementUnits, getParameters()).executeQuery();
//Go to the result count merge engine to execute the result set merge logic-"
            result = new ShardingResultSet(resultSets, new MergeEngine(
                    getShardingConnection().getShardingContext().getDatabaseType(), resultSets, (SelectStatement) getRouteResult().getSqlStatement()).merge());
        } finally {
            clearBatch ();
        }
        setCurrentResultSet(result);
        return result;
    }

Create a result set merge engine object and enter the constructor

/**
 * Sharded result set merge engine.
 *
 * @author zhangliang
 */
public final class MergeEngine {
    
    private final DatabaseType databaseType;
    
    private final List<ResultSet> resultSets;
    
    private final SelectStatement selectStatement;
    
    private final Map<String, Integer> columnLabelIndexMap;
    
    public MergeEngine(final DatabaseType databaseType, final List<ResultSet> resultSets, final SelectStatement selectStatement) throws SQLException {
        this.databaseType = databaseType;
        this.resultSets = resultSets;
        this.selectStatement = selectStatement;
        columnLabelIndexMap = getColumnLabelIndexMap(resultSets.get(0));
    }

Get the source data of the result set

columnLabelIndexMap = getColumnLabelIndexMap(resultSets.get(0));
private Map<String, Integer> getColumnLabelIndexMap(final ResultSet resultSet) throws SQLException {
// Get the source data of resultSet
        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
        Map<String, Integer> result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
            result.put(SQLUtil.getExactlyValue(resultSetMetaData.getColumnLabel(i)), i);
        }
        return result;
    }

into this method

com.dangdang.ddframe.rdb.sharding.merger.MergeEngine#merge

/**
 * Merge result sets.
 *
 * @return merged result set
 * @throws SQLException SQL异常
 */
public ResultSetMerger merge() throws SQLException {//Result set merge business method
    selectStatement.setIndexForItems(columnLabelIndexMap);
    return decorate(build());
}

into this method

com.dangdang.ddframe.rdb.sharding.merger.MergeEngine#build

private ResultSetMerger build() throws SQLException {
// The sort item is not empty or the aggregate selection is not empty
        if (!selectStatement.getGroupByItems().isEmpty() || !selectStatement.getAggregationSelectItems().isEmpty()) {
// If the grouping item is the same as the sorting item, merge the result set in the stream-"
            if (selectStatement.isSameGroupByAndOrderByItems()) {
                return new GroupByStreamResultSetMerger(columnLabelIndexMap, resultSets, selectStatement, getNullOrderType());
            } else {
// Otherwise, merge the result set in memory, try to avoid this situation, it will take up a lot of memory = "
                return new GroupByMemoryResultSetMerger(columnLabelIndexMap, resultSets, selectStatement, getNullOrderType());
            }
        }
        if (!selectStatement.getOrderByItems().isEmpty()) {
            return new OrderByStreamResultSetMerger(resultSets, selectStatement.getOrderByItems(), getNullOrderType());
        }
        return new IteratorStreamResultSetMerger(resultSets);
    }
return new GroupByStreamResultSetMerger(columnLabelIndexMap, resultSets, selectStatement, getNullOrderType());

 

Create a grouped streaming result set merge and enter the constructor method

public GroupByStreamResultSetMerger(
        final Map<String, Integer> labelAndIndexMap, final List<ResultSet> resultSets, final SelectStatement selectStatement, final OrderType nullOrderType) throws SQLException {
    super(resultSets, selectStatement.getOrderByItems(), nullOrderType);
    this.labelAndIndexMap = labelAndIndexMap;
    this.selectStatement = selectStatement;
    currentRow = new ArrayList<>(labelAndIndexMap.size());
    currentGroupByValues = getOrderByValuesQueue().isEmpty() ? Collections.emptyList() : new GroupByValue(getCurrentResultSet(), selectStatement.getGroupByItems()).getGroupValues();
}

this line of code

super(resultSets, selectStatement.getOrderByItems(), nullOrderType);

Create a sorted streaming result set merge object

public OrderByStreamResultSetMerger(final List<ResultSet> resultSets, final List<OrderItem> orderByItems, final OrderType nullOrderType) throws SQLException {
        this.orderByItems = orderByItems;
// Priority queue implementation
        this.orderByValuesQueue = new PriorityQueue<>(resultSets.size());
        this.nullOrderType = nullOrderType;
// Put the result set to be sorted into the queue-"
        orderResultSetsToQueue (resultSets);
        isFirstNext = true;
    }
// Put the result set to be sorted into the queue-"
        orderResultSetsToQueue (resultSets);
private void orderResultSetsToQueue(final List<ResultSet> resultSets) throws SQLException {
        for (ResultSet each : resultSets) {
            OrderByValue orderByValue = new OrderByValue (each, orderByItems, nullOrderType);
            if (orderByValue.next()) {
                orderByValuesQueue.offer(orderByValue);
            }
        }
// Stream result set merge, set the current stream merge result set, everyone sees that the current result set is stored here, so there will be no memory overflow problem
        setCurrentResultSet(orderByValuesQueue.isEmpty() ? resultSets.get(0) : orderByValuesQueue.peek().getResultSet());
    }

return to this method

private ResultSetMerger build() throws SQLException {
// The sort item is not empty or the aggregate selection is not empty
        if (!selectStatement.getGroupByItems().isEmpty() || !selectStatement.getAggregationSelectItems().isEmpty()) {
// If the grouping item is the same as the sorting item, merge the result set in the stream-"
            if (selectStatement.isSameGroupByAndOrderByItems()) {
                return new GroupByStreamResultSetMerger(columnLabelIndexMap, resultSets, selectStatement, getNullOrderType());
            } else {
// Otherwise, merge the result set in memory, try to avoid this situation, it will take up a lot of memory = "
                return new GroupByMemoryResultSetMerger(columnLabelIndexMap, resultSets, selectStatement, getNullOrderType());
            }
        }
        if (!selectStatement.getOrderByItems().isEmpty()) {
            return new OrderByStreamResultSetMerger(resultSets, selectStatement.getOrderByItems(), getNullOrderType());
        }
        return new IteratorStreamResultSetMerger(resultSets);
    }

this line

// Otherwise, merge the result set in memory, try to avoid this situation, it will take up a lot of memory = "
                return new GroupByMemoryResultSetMerger(columnLabelIndexMap, resultSets, selectStatement, getNullOrderType());

Create an in-memory grouped result set merge object

public GroupByMemoryResultSetMerger(
            final Map<String, Integer> labelAndIndexMap, final List<ResultSet> resultSets, final SelectStatement selectStatement, final OrderType nullOrderType) throws SQLException {
        super(labelAndIndexMap);
        this.selectStatement = selectStatement;
        this.nullOrderType = nullOrderType;
// Create an in-memory result set row object
        memoryResultSetRows = init(resultSets);
    }

return to this method

private ResultSetMerger build() throws SQLException {
// The sort item is not empty or the aggregate selection is not empty
        if (!selectStatement.getGroupByItems().isEmpty() || !selectStatement.getAggregationSelectItems().isEmpty()) {
// If the grouping item is the same as the sorting item, merge the result set in the stream-"
            if (selectStatement.isSameGroupByAndOrderByItems()) {
                return new GroupByStreamResultSetMerger(columnLabelIndexMap, resultSets, selectStatement, getNullOrderType());
            } else {
// Otherwise, merge the result set in memory, try to avoid this situation, it will take up a lot of memory = "
                return new GroupByMemoryResultSetMerger(columnLabelIndexMap, resultSets, selectStatement, getNullOrderType());
            }
        }
        if (!selectStatement.getOrderByItems().isEmpty()) {
            return new OrderByStreamResultSetMerger(resultSets, selectStatement.getOrderByItems(), getNullOrderType());
        }
// Create an iterative merge result set merge object
        return new IteratorStreamResultSetMerger(resultSets);
    }

this line

// Create an iterative merge result set merge object
        return new IteratorStreamResultSetMerger(resultSets);
public IteratorStreamResultSetMerger(final List<ResultSet> resultSets) {
    this.resultSets = resultSets.iterator();
    setCurrentResultSet(this.resultSets.next());
}

return to this method

/**
 * Merge result sets.
 *
 * @return merged result set
 * @throws SQLException SQL异常
 */
public ResultSetMerger merge() throws SQLException {//Result set merge business method
    selectStatement.setIndexForItems(columnLabelIndexMap);
    return decorate(build());
}

Enter this method com.dangdang.ddframe.rdb.sharding.merger.MergeEngine#decorate

private ResultSetMerger decorate(final ResultSetMerger resultSetMerger) throws SQLException {
        ResultSetMerger result = resultSetMerger;
        if (null != selectStatement.getLimit()) {
// The decorator pattern further encapsulates the paging result set merging
            result = new LimitDecoratorResultSetMerger(result, selectStatement.getLimit());
        }
        return result;
    }

 

The result set merge source code parsing ends here.

 

 

to the end

There are a lot of content in the source code analysis. It is more intuitive to look at the source code directly. The source code analysis here is just to give you an idea of ​​​​reading the source code. I have tried my best to introduce the key points of sharding-jdbc implementation. There may be other The good implementation has not been introduced. The sharding-jdbc source code analysis series is all over here. If you need further in-depth communication, please add me on WeChat, and I will pull you to the Tianhechat technology discussion group to communicate with each other. The above source code analysis for reference only.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325462710&siteId=291194637