Apache DbUtils: обработка нескольких наборов результатов, возвращаемых хранимой процедурой

У меня проблема с использованием DbUtils для получения результатов хранимой процедуры в SQL Server.

Хранимая процедура при выполнении в SQL Server Management Studio возвращает два отдельных набора результатов при выполнении для определенного входного значения, но для других значений она возвращает только один набор результатов. Следующие изображения иллюстрируют проблему:

Возвращен один набор результатов: Результаты с данными 1 таблицы

Возвращено два набора результатов: Результат с данными из 2 таблиц

Проблема, с которой я столкнулся, заключается в том, что я использую DbUtils BeanListHandler для преобразования результатов в список UserInfo компонентов.

List<UserInfo> userList = (List<UserInfo>) run.query(STORED_PROC, new BeanListHandler(UserInfo.class), refId);

Когда хранимая процедура возвращает только один набор результатов, она работает нормально. Однако в случае, когда возвращаются два набора результатов, выдается только список для первого набора результатов.

Я думаю, что с помощью JDBC мы можем использовать несколько ResultSet, но я не уверен, как обращаться с этим DbUtils.

Может ли кто-нибудь дать представление? Если требуется какая-либо другая информация, пожалуйста, обновите меня, я предоставлю.


person Ankit Nigam    schedule 14.04.2016    source источник
comment
Кто-нибудь может помочь. Я не ясно относительно моего запроса?   -  person Ankit Nigam    schedule 14.04.2016
comment
Вы можете опубликовать содержимое хранимой процедуры?   -  person Dave    schedule 15.04.2016
comment
@Dave Дэйв, у меня нет доступа к запросу в Stored Proc. Я могу только выполнить его, чтобы получить результаты.   -  person Ankit Nigam    schedule 15.04.2016
comment
Что представляет собой возвращаемое значение @return_value (т. е. что оно используется для определения... ошибки, возвращает конкретное значение, которое требуется в другом месте)?   -  person Dave    schedule 15.04.2016
comment
В Javadocs для DbUtils не упоминается множественный результат. наборы. Хотя это может быть не ваш предпочтительный подход, можете ли вы, по крайней мере, воспользоваться возможностью использовать JDBC CallableStatement, получить различные наборы результатов и построить свой список объектов таким образом?   -  person Gord Thompson    schedule 15.04.2016
comment
@Dave Этот код выглядит как стандартный T-SQL, который SQL Server Management Studio генерирует, когда вы щелкаете правой кнопкой мыши хранимую процедуру в обозревателе объектов и выбираете «Выполнить хранимую процедуру» .... Очевидно, я не могу узнать, действительно ли это так. важно в данном конкретном случае, но я как бы сомневаюсь в этом.   -  person Gord Thompson    schedule 15.04.2016
comment
@GordThompson да, я использовал CallableStatement с Native JDBC, и это сработало. Но это был бы длительный процесс и код. Любой способ сделать это короче, используя Pojo/Beans, например UserInfo, который я использую с DbUtils.   -  person Ankit Nigam    schedule 15.04.2016
comment
@GordThompson ... согласился ... как я уже упоминал ниже, и, честно говоря, возвращать несколько результатов SP - это плохой тон, и идеальным решением было бы вернуть один результат таблицы, как в варианте 1). Я парень .net и никогда не использовал JDBC, и могут быть варианты работы с несколькими наборами записей в JDBC, но я не знаком. Просто отвечал на сторону T SQL.   -  person Dave    schedule 15.04.2016
comment
Рассматривали ли вы создание подкласса org.apache.commons.dbutils.QueryRunner и переопределение соответствующих методов .query кодом, использующим PreparedStatement#getMoreResults()?   -  person Gord Thompson    schedule 16.04.2016
comment
@GordThompson спасибо за указатель (y) Посмотрю на это   -  person Ankit Nigam    schedule 16.04.2016


Ответы (2)


Было бы достаточно просто создать подкласс объекта QueryRunner, а затем настроить соответствующий метод(ы) query для обработки нескольких наборов результатов. С помощью следующего кода я смог получить полный список объектов UserInfo, используя

ResultSetHandler<List<UserInfo>> h = new BeanListHandler<UserInfo>(UserInfo.class);
MyQueryRunner run = new MyQueryRunner(ds);
String sql = 
        "EXEC dbo.Gain_Web_GetCompanyRepByIndRefID @RefID=?";
List<UserInfo> result = run.query(sql, h, 2);

где MyQueryRunner

package com.example.so36623732;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import javax.sql.DataSource;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;

public class MyQueryRunner extends QueryRunner {

    public MyQueryRunner(DataSource ds) {
        super(ds);
    }

    /**
     * Executes the given SELECT or EXEC SQL query and returns a result object.
     * The <code>Connection</code> is retrieved from the
     * <code>DataSource</code> set in the constructor.
     * @param <T> The type of object that the handler returns
     * @param sql The SQL statement to execute.
     * @param rsh The handler used to create the result object from
     * the <code>ResultSet</code>.
     * @param params Initialize the PreparedStatement's IN parameters with
     * this array.
     * @return An object generated by the handler.
     * @throws SQLException if a database access error occurs
     */
    public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
        Connection conn = this.prepareConnection();

        return this.<T>query(conn, true, sql, rsh, params);
    }

    /**
     * Calls query after checking the parameters to ensure nothing is null.
     * @param conn The connection to use for the query call.
     * @param closeConn True if the connection should be closed, false otherwise.
     * @param sql The SQL statement to execute.
     * @param params An array of query replacement parameters.  Each row in
     * this array is one set of batch replacement values.
     * @return The results of the query.
     * @throws SQLException If there are database or parameter errors.
     */
    @SuppressWarnings("unchecked")
    private <T> T query(Connection conn, boolean closeConn, String sql, ResultSetHandler<T> rsh, Object... params)
            throws SQLException {
        if (conn == null) {
            throw new SQLException("Null connection");
        }

        if (sql == null) {
            if (closeConn) {
                close(conn);
            }
            throw new SQLException("Null SQL statement");
        }

        if (rsh == null) {
            if (closeConn) {
                close(conn);
            }
            throw new SQLException("Null ResultSetHandler");
        }

        PreparedStatement stmt = null;
        ResultSet rs = null;
        T result = null;
        List<T> allResults = null;

        try {
            stmt = this.prepareStatement(conn, sql);
            this.fillStatement(stmt, params);
            rs = this.wrap(stmt.executeQuery());
            allResults = (List<T>)rsh.handle(rs);
            while (stmt.getMoreResults()) {
                rs = stmt.getResultSet();
                result = rsh.handle(rs);
                allResults.addAll((List<T>)result);
            }

        } catch (SQLException e) {
            this.rethrow(e, sql, params);

        } finally {
            try {
                close(rs);
            } finally {
                close(stmt);
                if (closeConn) {
                    close(conn);
                }
            }
        }

        return (T) allResults;
    }

}
person Gord Thompson    schedule 19.05.2016
comment
классно. Спасибо :) - person Ankit Nigam; 01.06.2016

Честно говоря, если эта хранимая процедура возвращает 2 набора результатов за одно выполнение, у вас большие проблемы. В идеале вы хотите, чтобы 2 результата возвращались в виде одной таблицы из SP, и тогда все будет в порядке.

1) Попробуйте связаться с человеком, имеющим доступ к SP, и доведите до его сведения ваш случай. Попросите их создать временную таблицу для хранения всех записей из двух возвращаемых результатов, а затем просто вернуть все содержимое этой временной таблицы.

2) Если у вас нет этой опции, вы можете попробовать процесс, описанный в этой статье -multiple-result-sets">получить-данные-из-хранимой-процедуры-которая-имеет-множество-результатов, чтобы получить результаты, если вы не можете получить какое-либо движение от 1)

ХТН

Дэйв

person Dave    schedule 15.04.2016
comment
Спасибо за ответ. Я пытался использовать собственный Jdbc, и это работало с несколькими наборами результатов, но этот код длинный. Есть ли способ или Api, похожий на Dbutils, мы можем изменить это на быстрый код с помощью Beans/Pojo - person Ankit Nigam; 15.04.2016