Xử lý kết quả truy vấn trong MyBatis qua ResultSetHandler

Sau khi xử lý xong StatementHandlerParameterHandler, bước tiếp theo là chuyển đổi dữ liệu trả về từ cơ sở dữ liệu thành các đối tượng Java — công việc này do ResultSetHandler đảm nhiệm. Giao diện này nằm trong package org.apache.ibatis.executor.resultset, với định nghĩa như sau:

public interface ResultSetHandler {
  <E> List<E> handleResultSets(Statement stmt) throws SQLException;
  <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
  void handleOutputParameters(CallableStatement cs) throws SQLException;
}

Hai phương thức đầu dùng để xử lý tập kết quả từ câu lệnh SQL thông thường, còn phương thức cuối dành riêng cho stored procedure có tham số đầu ra. Trong bài này, ta tập trung vào phương thức handleResultSets.

Lớp triển khai mặc định là DefaultResultSetHandler, được khởi tạo thông qua Configuration như sau:

public ResultSetHandler newResultSetHandler(Executor executor, 
                                           MappedStatement stmt, 
                                           RowBounds bounds,
                                           ParameterHandler paramHandler,
                                           ResultHandler resultHandler, 
                                           BoundSql sql) {
    ResultSetHandler handler = new DefaultResultSetHandler(executor, stmt, 
                                                          paramHandler, resultHandler, 
                                                          sql, bounds);
    return (ResultSetHandler) interceptorChain.pluginAll(handler);
}

Dưới đây là phần cốt lõi của phương thức handleResultSets trong DefaultResultSetHandler:

@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(stmt.getId());

    List<Object> results = new ArrayList<>();
    int resultSetIndex = 0;
    ResultSetWrapper currentRS = getFirstResultSet(stmt);

    List<ResultMap> maps = stmt.getResultMaps();
    int mapCount = maps.size();
    validateResultMapsCount(currentRS, mapCount);

    while (currentRS != null && resultSetIndex < mapCount) {
        ResultMap currentMap = maps.get(resultSetIndex);
        handleResultSet(currentRS, currentMap, results, null);
        currentRS = getNextResultSet(stmt);
        cleanUpAfterHandlingResultSet();
        resultSetIndex++;
    }

    String[] resultSetNames = stmt.getResultSets();
    if (resultSetNames != null) {
        while (currentRS != null && resultSetIndex < resultSetNames.length) {
            ResultMapping parentMap = nextResultMaps.get(resultSetNames[resultSetIndex]);
            if (parentMap != null) {
                String nestedMapId = parentMap.getNestedResultMapId();
                ResultMap nestedMap = configuration.getResultMap(nestedMapId);
                handleResultSet(currentRS, nestedMap, null, parentMap);
            }
            currentRS = getNextResultSet(stmt);
            cleanUpAfterHandlingResultSet();
            resultSetIndex++;
        }
    }

    return collapseSingleResultList(results);
}

Quá trình xử lý bao gồm: lấy từng ResultSet, ánh xạ dữ liệu theo ResultMap tương ứng, dọn dẹp trạng thái sau mỗi lần xử lý, và cuối cùng trả về danh sách kết quả đã được chuyển đổi.

Thẻ: mybatis ResultSetHandler DefaultResultSetHandler ResultMap SQL Mapping

Đăng vào ngày 2 tháng 6 lúc 23:32