Как правильно очистить ресурсы JDBC в Java? - PullRequest
8 голосов
/ 22 декабря 2010

Что считается наилучшей практикой при очистке ресурсов JDBC и почему? Я сохранил пример коротким, поэтому просто очистил ResultSet.

finally
{
  if(rs != null)
    try{ rs.close(); } catch(SQLException ignored) {}
}

против

finally
{
  try{ rs.close(); } catch(Exception ignored) {}
}

Лично я предпочитаю второй вариант, так как он немного короче. Любой вклад в это очень ценится.

Ответы [ 9 ]

10 голосов
/ 08 февраля 2012

В настоящее время JDK 7 предоставляет вам самый простой способ очистки ресурсов:

String query = "select COF_NAME, PRICE from COFFEES";
try (Statement stmt = con.createStatement()) {
    ResultSet rs = stmt.executeQuery(query);
    while (rs.next()) {
        String coffeeName = rs.getString("COF_NAME");
        float price = rs.getFloat("PRICE");
        System.out.println(coffeeName + ", "  + price);
    }
}

Оператор try обеспечивает закрытие каждого ресурса в конце оператора. Смотри http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

4 голосов
/ 22 декабря 2010

Как отмечали другие, ресурсы JDBC (операторы, наборы результатов и т. Д.) Редко бывают null.Если это так, у вас на руках больше проблем, чем NullPointerException s.В связи с этим NullPointerException s поможет предупредить вас о серьезных проблемах с вашим драйвером JDBC.Типичная проверка null перед вызовом close() скрыла бы проблему, если бы ваш драйвер JDBC фактически предоставлял вам null ссылки.

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

На практике я нашел этот приемполезный (хотя и не самый красивый):

PreparedStatement statement = connection.prepareStatement("...");
try {
    ResultSet results = statement.executeQuery();
    try {
        while (results.next()) {
            // ...
        }
    } finally {
        results.close();
    }
} finally {
    statement.close();
}

Этот метод гарантирует выполнение каждого оператора close(), начиная с ResultSet и продолжая свой путь наружу.NullPointerException s все еще выбрасываются, если драйвер предоставит вам null ссылки, но я допускаю это по причинам, объясненным в начале.SQLException все еще выбрасываются, если какое-либо из операторов close() не выполняется (я считаю, что это хорошо - я хочу знать, если что-то идет не так).

3 голосов
/ 22 декабря 2010

Не вижу проблем с вашей второй (необычной) версией.

  • обычно, rs не будет null, поэтому в редких случаях возникает NPE. Так что я не вижу здесь проблем с производительностью.
  • обе версии ведут себя одинаково в случае rs = null

Единственный недостаток - если у нас есть более одного ресурса для закрытия, то мы должны добавить одну попытку / ловлю для каждого ресурса, если мы хотим закрыть как можно больше ресурсов. В противном случае мы введем предложение catch с первым null, и это может привести к недисциплинированным утечкам.

Так это будет выглядеть так:

finally {
   try{rs.close();  }catch(Exception ignored){}
   try{stmt.close();}catch(Exception ignored){}
   try{conn.close();}catch(Exception ignored){}
}

... который все еще читается и понятен. Но, согласно , никогда не меняйте общий шаблон - я бы придерживался старомодного способа сначала проверить null и поймать SQLException при закрытии.

2 голосов
/ 18 ноября 2014
public static void close(Statement... statements) {
        for (Statement stmt : statements) {
            try {
                if (stmt != null)
                    stmt.close();
            } catch (SQLException se) {
            }// nothing we can do
        }
    }

    public static void close(Connection conn) {
        try {
            if (conn != null)
                conn.close();
        } catch (SQLException se) {
        }// nothing we can do
    }
public static void close(ResultSet rs) {
        try {
            if (rs != null) 
                rs.close();
        } catch (SQLException se) {
        }// nothing we can do
}
2 голосов
/ 22 декабря 2010

Я склонен использовать следующий подход. Я думаю, что стоит проверить null, потому что это показывает ваше намерение, т. Е. Вы понимаете, что эти объекты могут быть нулевыми в редких случаях. (Нулевая проверка также быстрее, чем создание NullPointerException.) Я также думаю, что лучше регистрировать исключения, а не проглатывать их. В случаях, когда close терпит неудачу, я хочу знать об этом и иметь это в моих файлах журнала.

finally {            
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                 LOG.warn("Failed to close rs", e);
                }
            }
            if (st != null) {
                try {
                    st.close();
                } catch (SQLException e) { 
                 LOG.warn("Failed to close st", e);     
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                 LOG.warn("Failed to close conn", e);
                }
            }
        }

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

С помощью DBUtils вы можете выполнить эту очистку довольно кратко, как указано ниже:

 finally {            
            DBUtils.closeQuietly(rs);
            DBUtils.closeQuietly(st);
            DBUtils.closeQuietly(conn);            
        }
1 голос
/ 17 января 2012

Это мой подход к JDK 6. Если у вас JDK 7+, вам лучше использовать подход, который я описал здесь https://stackoverflow.com/a/9200053/259237

private void querySomething() {
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet rs = null;
    try {
        // get connection
        // prepare statement
        // execute query
        // and so on
    } catch (SQLException e) {
        throw new MyException("Error while talking to database", e);
    } finally {
        close(connection, statement, rs);
    }
}

// useful because you probably have more than one method interacting with database
public static void close (Connection connection, Statement statement, ResultSet rs) {
    if (rs != null) {
        try { rs.close(); } catch (Exception e) { _logger.warning(e.toString()); }
    }
    if (statement != null) {
        try { statement.close(); } catch (Exception e) { _logger.warning(e.toString()); }
    }
    if (connection != null) {
        try { connection.close(); } catch (Exception e) { _logger.warning(e.toString()); }
    }
}
  • Это коротко.
  • Определяет метод close, который может быть статически импортирован.
  • Избегает пустых блоков захвата.
  • Он обрабатывает любые исключения SQLE, которые могут возникнуть (даже в методах getConnection или close).
  • Это абсолютно безопасно.
0 голосов
/ 22 декабря 2010
protected void closeAll(){
        closeResultSet();
        closeStatement();
        closeConnection();
    }   

protected void closeConnection(){
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                /*Logger*/
            }
            connection = null;
        }
    }


    protected void closeStatement() {
        if (stmt != null) {
            try {
                ocstmt.close();
            } catch (SQLException e) {
                /*Logger*/
            }
            ocstmt = null;
        }
    }


    protected void closeResultSet() {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                /*Logger*/
            }
            rs = null;
        }
    }
0 голосов
/ 22 декабря 2010

Если вы пишете долго работающее приложение, вам следует подумать о пуле соединений.

Проект Apache DBCP выполняет большую часть этой работы за вас.Вы также можете взглянуть на что-то вроде Spring JDBC или Hibernate.

В Spring используются пулы объектов и добавлены некоторые действительно хорошие методы для абстрагирования от вредоносности JDBC.

0 голосов
/ 22 декабря 2010
ResultSet rs = //initialize here
try {
  // do stuff here
} finally {
  try { rs.close(); }
  catch(SQLException ignored) {}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...