Получение java.sql.SQLException: операция не разрешена после закрытия результирующего набора

#java #mysql #jdbc #prepared-statement #resultset

#java #mysql #jdbc #подготовленное утверждение #результирующий набор

Вопрос:

Когда я выполняю следующий код, я получаю исключение. Я думаю, это потому, что я готовлю инструкцию in new с тем же объектом connection. Как мне переписать это, чтобы я мог создать подготовленную инструкцию и использовать rs2? Должен ли я создавать новый объект connection, даже если соединение подключено к той же БД?

     try 
    {
        //Get some stuff
        String name = "";
        String sql = "SELECT `name` FROM `user` WHERE `id` = "   userId   " LIMIT 1;";
        ResultSet rs = statement.executeQuery(sql);
        if(rs.next())
        {
            name = rs.getString("name");
        }

        String sql2 = "SELECT `id` FROM  `profiles` WHERE `id` ="   profId   ";";
        ResultSet rs2 = statement.executeQuery(sql2);
        String updateSql = "INSERT INTO `blah`............"; 
        PreparedStatement pst = (PreparedStatement)connection.prepareStatement(updateSql);    

        while(rs2.next()) 
        { 
            int id = rs2.getInt("id");
            int stuff = getStuff(id);

            pst.setInt(1, stuff);
            pst.addBatch();

        }

        pst.executeBatch();

    } 
    catch (Exception e) 
    {
        e.printStackTrace();
    }

private int getStuff(int id)
{

    try
    {   

            String sql = "SELECT ......;";
            ResultSet rs = statement.executeQuery(sql);

            if(rs.next())
            {
                return rs.getInt("something");

            }
            return -1;
    }//code continues
  

Комментарии:

1. это происходит в первый раз, когда вызывается while?

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

3. можете ли вы отобразить остальную часть кода, который выполняется на первой итерации

4. Может ли исключение произойти из-за этого другого результирующего набора?

Ответ №1:

Проблема в том, как вы извлекаете данные getStuff() . Каждый раз, когда вы посещаете, getStuff() вы получаете новое ResultSet сообщение, но не закрываете его.

Это нарушает ожидания Statement класса (смотрите здесь — http://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html ):

По умолчанию одновременно может быть открыт только один объект результирующего набора для каждого объекта инструкции. Следовательно, если чтение одного объекта результирующего набора чередуется с чтением другого, каждый из них, должно быть, был сгенерирован разными объектами Statement. Все методы выполнения в интерфейсе Statement неявно закрывают текущий объект ResultSet statment, если существует открытый объект.

Что делает ситуацию еще хуже, так это rs из вызывающего кода. Оно также является производным от statement поля, но оно не закрыто.

Итог: у вас одновременно открыто несколько объектов, ResultSet относящихся к одному и тому же Statement объекту.

Комментарии:

1. Прохладный. Я создал новый оператор в GetStuff (), и это решило проблему.

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

Ответ №2:

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

Я предполагаю, что после while(rs2.next()) вы пытаетесь получить доступ к чему-либо из rs1. Но он уже закрыт, поскольку вы повторно выполнили инструкцию, чтобы получить из нее rs2. Поскольку вы не закрыли его, я полагаю, что он снова используется ниже.

Комментарии:

1. Просто добавлено больше кода. На самом деле я ничего не получаю от rs1 впоследствии.

2. эти древние классы Java так странно спроектированы : (