Подтвердить что ты не робот

Где закрыть java PreparedStatements и ResultSets?

Рассмотрим код:

PreparedStatement ps = null;
ResultSet rs = null;
try {
  ps = conn.createStatement(myQueryString);
  rs = ps.executeQuery();
  // process the results...
} catch (java.sql.SQLException e) {
  log.error("an error!", e);
  throw new MyAppException("I'm sorry. Your query did not work.");
} finally {
  ps.close();
  rs.close();
}

Вышеприведенное не компилируется, потому что оба PreparedStatement.close() и ResultSet.close() бросают a java.sql.SQLException. Так я добавляю блок try/catch в предложение finally? Или переместить тесные утверждения в предложение try? Или просто не беспокоиться о вызове?

4b9b3361

Ответ 1

Для ввода/вывода файлов я обычно добавляю try/catch к блоку finally. Тем не менее, вы должны быть осторожны, чтобы не исключать какие-либо исключения из блока finally, поскольку они заставят исходное исключение (если оно есть) потеряться.

См. эту статью для более конкретного примера закрытия подключения к базе данных.

Ответ 2

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

Exception in try | Exception in close | Result
-----------------+--------------------+----------------------------------------
      No         |        No          | Continue normally
      No         |        Yes         | Throw the close() exception
      Yes        |        No          | Throw the exception from try block
      Yes        |        Yes         | Add close() exception to main exception
                 |                    |  as "suppressed", throw main exception

Надеюсь, это имеет смысл. In позволяет довольно кодовый код, например:

private void doEverythingInOneSillyMethod(String key)
  throws MyAppException
{
  try (Connection db = ds.getConnection()) {
    db.setReadOnly(true);
    ...
    try (PreparedStatement ps = db.prepareStatement(...)) {
      ps.setString(1, key);
      ...
      try (ResultSet rs = ps.executeQuery()) {
        ...
      }
    }
  } catch (SQLException ex) {
    throw new MyAppException("Query failed.", ex);
  }
}

До Java 7 лучше всего использовать вложенные блоки finally, а не тестировать ссылки для нулевого.

Пример, который я покажу, может выглядеть уродливым с глубоким вложением, но на практике хорошо продуманный код, вероятно, не будет создавать соединение, оператор и результаты в одном и том же методе; часто каждый уровень вложенности включает передачу ресурса другому методу, который использует его как factory для другого ресурса. При таком подходе исключения из close() будут маскировать исключение изнутри блока try. Это можно преодолеть, но это приводит к еще более беспорядочному коду и требует настраиваемого класса исключений, который обеспечивает "подавленную" цепочку исключений, присутствующих в Java 7.

Connection db = ds.getConnection();
try {
  PreparedStatement ps = ...;
  try {
    ResultSet rs = ...
    try {
      ...
    }
    finally {
      rs.close();
    }
  } 
  finally {
    ps.close();
  }
} 
finally {
  db.close();
}

Ответ 3

Если вы действительно раскалываете свой собственный jdbc, он определенно становится беспорядочным. Закрытие() в конечном итоге должно быть обернуто собственной попыткой catch, которая, по крайней мере, является уродливой. Вы не можете пропустить закрытие, хотя ресурсы будут очищены, когда соединение будет закрыто (что может быть не так, если вы используете пул). Фактически, одним из основных преимуществ использования фреймворка (например, спящего режима) для управления доступом к базе данных является управление связью и обработка набора результатов, чтобы вы не забыли закрыть.

Вы можете сделать что-то простое, как это, что, по крайней мере, скрывает беспорядок, и гарантирует, что вы ничего не забудете.

public static void close(ResultSet rs, Statement ps, Connection conn)
{
    if (rs!=null)
    {
        try
        {
            rs.close();

        }
        catch(SQLException e)
        {
            logger.error("The result set cannot be closed.", e);
        }
    }
    if (ps != null)
    {
        try
        {
            ps.close();
        } catch (SQLException e)
        {
            logger.error("The statement cannot be closed.", e);
        }
    }
    if (conn != null)
    {
        try
        {
            conn.close();
        } catch (SQLException e)
        {
            logger.error("The data source connection cannot be closed.", e);
        }
    }

}

а затем

finally {
    close(rs, ps, null); 
}

Ответ 4

Не тратьте свое время на кодирование управления исключениями низкого уровня, используйте API более высокого уровня, например Spring -JDBC, или пользовательскую оболочку вокруг объектов connection/statement/rs, чтобы скрыть беспорядочный код проверки try-catch.

Ответ 5

Также обратите внимание:

"Когда объект Statement закрыт, его текущий объект ResultSet, если он существует, также закрыт."

http://java.sun.com/j2se/1.5.0/docs/api/java/sql/Statement.html#close()

Достаточно закрыть только PreparedStatement в конце, и только если он еще не закрыт. Если вы хотите быть действительно особенным, закройте ResultSet FIRST, а не после закрытия PreparedStatement (закрытие его после, как и некоторые из примеров здесь, должно фактически гарантировать исключение, так как оно уже закрыто).

Ответ 6

У меня обычно есть метод утилиты, который может закрывать такие вещи, в том числе стараться не делать ничего с нулевой ссылкой.

Обычно, если close() выбрасывает исключение, мне на самом деле неинтересно, поэтому я просто регистрирую исключение и проглатываю его, но другой альтернативой было бы преобразование его в RuntimeException. В любом случае, я рекомендую сделать это в утилите, который легко вызвать, так как вам может понадобиться сделать это во многих местах.

Обратите внимание, что ваше текущее решение не будет закрывать ResultSet, если закрытие PreparedStatement не удастся - лучше использовать вложенные блоки finally.

Ответ 7

Если вы используете Java 7, вы можете использовать улучшения в механизмах обработки исключений в тех классах, которые реализуют AutoCloseable (т.е. PreparedStatement, Resultset)

Вы также можете найти этот вопрос интересным: Закрытие ResultSet в Java 7

Ответ 8

Я знаю, что это старый вопрос, но на всякий случай кто-то ищет ответ, у java теперь есть решение try-with-resouce.

static String readFirstLineFromFile(String path) throws IOException {
      try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

Ответ 9

Не закрывайте вызов. Это может вызвать проблемы.

Я предпочитаю добавить блок try/catch к окончательному.

Ответ 10

Вероятно, старый (хотя и простой) способ сделать что-то, но он все еще работает:

public class DatabaseTest {

    private Connection conn;    
    private Statement st;   
    private ResultSet rs;
    private PreparedStatement ps;

    public DatabaseTest() {
        // if needed
    }

    public String getSomethingFromDatabase(...) {
        String something = null;

        // code here

        try {
            // code here

        } catch(SQLException se) {
            se.printStackTrace();

        } finally { // will always execute even after a return statement
            closeDatabaseResources();
        }

        return something;
    }

    private void closeDatabaseResources() {
        try {
            if(conn != null) {
                System.out.println("conn closed");
                conn.close();
            }

            if(st != null) {
                System.out.println("st closed");
                st.close();
            }

            if(rs != null) {
                System.out.println("rs closed");
                rs.close();
            }

            if(ps != null) {
                System.out.println("ps closed");
                ps.close();
            }

        } catch(SQLException se) {
            se.printStackTrace();
        }               
    }
}

Ответ 11

Основываясь на ответе @erickson, почему бы просто не сделать это в одном блоке try, как это?

private void doEverythingInOneSillyMethod(String key) throws MyAppException
{
  try (Connection db = ds.getConnection();
       PreparedStatement ps = db.prepareStatement(...)) {

    db.setReadOnly(true);
    ps.setString(1, key);
    ResultSet rs = ps.executeQuery()
    ...
  } catch (SQLException ex) {
    throw new MyAppException("Query failed.", ex);
  }
}

Обратите внимание, что вам не нужно создавать объект ResultSet внутри блока try, поскольку ResultSet автоматически закрывается, когда объект PreparedStatement закрыт.

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

Ссылка: https://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html

Ответ 12

focus finally,

finally {
   try {
      rs.close();
      ps.close();
   } catch (Exception e) {
      // Do something
   }
}

Я думаю, вам нужно изменить 2 очка.

Во-первых, повторите попытку и поймайте в разделе fainlly.

Во-вторых, do rs.close() перед выполнением ps.close().

[email protected]

Ответ 13

Я использую это.

finally
{
    if (ps != null) ps.close();
    if (rs != null) rs.close();
}