Где закрыть соединение JDBC, в то время как я хочу возвратить ResultSet

Кажется что ResultSet будет автоматически закрыт, когда я закроюсь Connection. Но я хочу возвратиться ResultSet и используйте его в другом методе, затем я не знаю, где закрыться Connection и PreparedStatement.

public ResultSet executeQuery(String sql, String[] getValue)
{
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try
    {
        conn = getConn();
        pstmt = conn.prepareStatement(sql);
        if (getValue != null)
        {
            for (int i = 0; i < getValue.length; i++)
            {
                pstmt.setString(i + 1, getValue[i]);
            }
        }
        rs = pstmt.executeQuery();
    } catch (Exception e)
    {
        e.printStackTrace();
        closeAll(conn, pstmt, rs);
    }
    return rs;
}

Я переместился closeAll(conn, pstmt, null); в блок выгоды, потому что я нашел, что, если я вставил его наконец блок, я буду, потерял мой rs сразу непосредственно перед тем, как это возвращается. Теперь, когда я хочу закрыться rs, Я не могу закрыться conn и pstmt. Есть ли какое-либо решение?

18
задан bluish 5 March 2012 в 08:57
поделиться

9 ответов

Используйте CachedRowSet для хранения информации после отключения

Connection con = ...
ResultSet rs = ...

CachedRowSet rowset = new CachedRowSetImpl();
rowset.populate(rs);

con.close()
31
ответ дан 30 November 2019 в 05:47
поделиться

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

Другой метод создает объект с помощью метода обратного вызова с его обработкой resultSet код и передает его методу, который выполняет SQL.

Таким образом, ваш код SQL и DB остается там, где он принадлежит, логика обработки набора результатов ближе к тому, где вы используете данные, и ваш код SQL очищается, когда это должно быть.

  interface ResultSetCallBack{
    void handleResultSet(ResultSet r);
  }

  void executeQuery(..., ResultSetCallBack cb){
    //get resultSet r ...
    cb.handleResultSet(r);
    //close connection
  }

  void printReport(){
    executeQuery(..., new ResultSetCallBack(){
      public void handleResultSet(ResultSet r) {
        //do stuff with r here
      }
    });
  }
20
ответ дан 30 November 2019 в 05:47
поделиться

The way you have it right now, the connection would never close which would cause problems later (if not immediately) for your program and the RDBMS. It would be better to create a Java class to hold the fields from the ResultSet and return that. The ResultSet is linked to the connection, so returning it and closing the connection is not possible.

3
ответ дан 30 November 2019 в 05:47
поделиться

Вам действительно не следует работать с JDBC на нижнем уровне. Вместо этого используйте фреймворк, например spring , он выполнит все необходимые операции close () за вас.

1
ответ дан 30 November 2019 в 05:47
поделиться

Я бы порекомендовал вам сделать что-то подобное:

public List<Map> executeQuery(Connection connection, String sql) throws SQLException
{
    List<Map> rows = new ArrayList<Map>();

    PreparedStatement stmt = null;
    ResultSet rs = null;

    try
    {
        pstmt = conn.prepareStatement(sql);
        rs = stmt.execute();
        int numColumns = rs.getMetaData().getColumnCount();

        while (rs.next())
        {
            Map<String, Object> row = new LinkedHashMap<String, Object>();
            for (int i = 0; i < numColumns; ++i)
            {
                String column = rs.getColumnName(i+1);
                Object value = rs.getObject(i+1);
                row.put(column, value);
            }
            rows.add(row);
        }
    } 
    finally
    {
        close(rs);
        close(stmt);
    }

    return rows;
}

public static void close(Statement s)
{
    try
    {
        if (s != null)
        {
            s.close();
        }
    }
    catch (SQLException e)
    {
        e.printStackTrace();
    }
}

public static void close(ResultSet rs)
{
    try
    {
        if (rs != null)
        {
            rs.close();
        }
    }
    catch (SQLException e)
    {
        e.printStackTrace();
    }
}
1
ответ дан 30 November 2019 в 05:47
поделиться

Где закрыть соединение JDBC, когда я хочу вернуть ResultSet

На самом деле, вы почти сами ответили на этот вопрос. Как вы экспериментировали, закрытие соединения освободит ресурсы JDBC, связанные с ним (по крайней мере, так все должно работать). Итак, если вы хотите вернуть ResultSet (я вернусь к этому позже), вам нужно закрыть соединение «позже». Один из способов сделать это, очевидно, - передать подключение к вашему методу, примерно так:

public ResultSet executeQuery(Connection conn, String sql, String[] getValue);

Проблема в том, что я действительно не знаю, какова ваша конечная цель и почему вам нужны такие низкоуровневые вещи, поэтому я не уверен, что это хороший совет. Если вы не пишете фреймворк JDBC низкого уровня (и, пожалуйста, не говорите мне, что вы этого не делаете), На самом деле я бы не рекомендовал возвращать ResultSet . Например, если вы хотите накормить какой-то бизнес-класс, верните какой-нибудь JDBC-независимый объект или их коллекцию, как советовали другие, вместо ResultSet . Также имейте в виду, что RowSet - это ResultSet , поэтому, если вам не следует использовать ResultSet , то вам не следует использовать RowSet .

Лично я считаю, что вам следует использовать какой-нибудь вспомогательный класс вместо того, чтобы изобретать колесо. Хотя Spring может быть излишним и требует некоторого обучения (слишком много, если вы вообще этого не знаете), Spring - не единственный путь, и я настоятельно рекомендую взглянуть на Commons DbUtils . Более конкретно, посмотрите на QueryRunner и особенно на этот метод query () :

public <T> T query(String sql,
                   ResultSetHandler<T> rsh,
                   Object... params)
        throws SQLException

Как видите, этот метод позволяет передать ResultSetHandler , который предоставляет метод обратного вызова для преобразования ResultSets в другие объекты, как описано в ответе z5h , а DbUtils предоставляет несколько реализаций, просто выберите тот, который соответствует вашим потребностям. Также обратите внимание на служебные методы класса DbUtils , например различные DbUnit.close () , которые могут оказаться полезными для закрытия ресурсов JDBC.

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

просто выберите тот, который вам подходит. Также обратите внимание на служебные методы класса DbUtils , например различные DbUnit.close () , которые могут оказаться полезными для закрытия ресурсов JDBC.

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

просто выберите тот, который вам подходит. Также обратите внимание на служебные методы класса DbUtils , например различные DbUnit.close () , которые могут оказаться полезными для закрытия ресурсов JDBC.

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

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

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

3
ответ дан 30 November 2019 в 05:47
поделиться

Вы можете вызвать ResultSet.getStatement , чтобы получить Statement , и Statement.getConnection , чтобы получить соединение . .

Из них вы можете написать служебный метод closeResultSet , который закроет все 3 для вас, не имея ничего, кроме ResultSet .

3
ответ дан 30 November 2019 в 05:47
поделиться

Вы не можете использовать ResultSet после закрытия подключения и / или PreparedStatement . Итак, вам необходимо передать объект, для которого будет выполнен обратный вызов, в этот метод.

Вся очистка должна выполняться в блоках finally .

Перепишите его так

public ResultSet executeQuery(
    String sql,
    String[] getValue,
    CallbackObj cbObj
  ) throws SQLException
{
  final Connection conn = getConn( );

  try
  {
    final PreparedStatement pstmt = conn.prepareStatement(sql);

    try
    {
      if (getValue != null)
      {
        for (int i = 0; i < getValue.length; i++)
        {
          pstmt.setString(i + 1, getValue[i]);
        }
      }

      final ResultSet rs = pstmt.executeQuery();

      try
      {
        cbObj.processResultSet( rs );
      }
      finally
      {
        // You may want to handle SQLException
        // declared by close
        rs.close( );
      }
    }
    finally
    {
      // You may want to handle SQLException
      // declared by close
      pstmt.close( );
    }
  }
  finally
  {
    // You may want to handle SQLException
    // declared by close
    conn.close( );
  }
}
3
ответ дан 30 November 2019 в 05:47
поделиться

Вы не должны никогда передавать ResultSet (или Statement или Connection ) в открытый доступ за пределами блок метода, в котором они должны быть получены, и закрываются, чтобы избежать утечки ресурсов. Обычной практикой является просто отображение ResultSet в List , где Data - это просто объект javabean, представляющий интересующие данные.

Вот. базовый пример:

public class Data {
    private Long id;
    private String name;
    private Integer value;
    // Add/generate public getters + setters.
}

и вот базовый пример того, как с ним работать правильно:

public List<Data> list() throws SQLException {
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet resultSet = null;
    List<Data> list = new ArrayList<Data>();

    try {
        connection = database.getConnection();
        statement = connection.prepareStatement("SELECT id, name, value FROM data");
        resultSet = statement.executeQuery();
        while (resultSet.next()) {
            Data data = new Data();
            data.setId(resultSet.getLong("id"));
            data.setName(resultSet.getString("name"));
            data.setValue(resultSet.getInt("value"));
            list.add(data);
        }
    } finally {
        if (resultSet != null) try { resultSet.close(); } catch (SQLException logOrIgnore) {}
        if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {}
        if (connection != null) try { connection.close(); } catch (SQLException logOrIgnore) {}
    }

    return list;
}

вы можете использовать его следующим образом:

List<Data> list = dataDAO.list();

Чтобы узнать больше о передовых методах работы с JDBC, вы можете найти этот базовый запуск статья тоже полезна.

5
ответ дан 30 November 2019 в 05:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: