Java закрывает соединения и находит ошибки - PullRequest
3 голосов
/ 09 декабря 2010

В нашем коде мы обычно используем следующий шаблон:

Connection conn;
try{
    conn = getConnection();
    //Do databasey stuff
}catch(Exceptions that get thrown){
}finally{
    try{
        conn.close();
    }catch(SQLException ex){
        logger.error("Failed to cleanup database connection",ex);
    }
}

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

Редактировать: Добавлена ​​удаленная попытка перехвата закрытия.

Ответы [ 6 ]

6 голосов
/ 18 августа 2011

Что вы действительно хотите сделать, так это объединить ответ «The Elite Gentleman» с аннотацией @edu.umd.cs.findbugs.annotations.SuppressWarnings( "OBL_UNSATISFIED_OBLIGATION" ).Похоже, что FindBugs будет счастлив, если вы завершите метод закрытия следующим образом (что является предпочтительной последовательностью для этого):

...
}finally{
    try{ 
       resultSet.close();
    }catch( SqlException e ){
       //log error
    }finally{
       try{
          statement.close();
       }catch( SqlException e ){
          //log error
       }finally{
          try{
              connection.close();
          }catch( SqlException e ){
              //log error
          }
       }
    }
}

Это очень многословно, и вы, вероятно, не хотитеДелайте это, если не по какой-либо другой причине, кроме любви к вашему запястному туннелю, поэтому вы должны использовать метод DBUtils.closeQuietly() (или создать свой собственный вызов).Однако FindBugs не распознает это (т. Е. Используя библиотеку или свой собственный метод) как правильное закрытие ресурсов и выдает предупреждение.В этом случае это явно ложный положительный результат .Поэтому убедитесь, что это единственное предупреждение, которое вы получаете, а затем отключите это специальное предупреждение для этого метода.

@edu.umd.cs.findbugs.annotations.SuppressWarnings( "OBL_UNSATISFIED_OBLIGATION" )
public void doStuff( final Connection connection ){
    try{
        //Do databasey stuff
    }catch( SqlException e ){
        //throw a glorious exception....
    }finally{
        DbUtils.closeQuietly( resultSet  );
        DbUtils.closeQuietly( statement  );
        DbUtils.closeQuietly( connection );
}

Таким образом вы очищаете свои ресурсы с помощью нескольких строк кода и избегаете предупреждения FindBugs.

6 голосов
/ 09 декабря 2010

Уже есть утилита, которая делает то, что упомянуло @duffymo: DbUtils от Apache.

  • DbUtils.close(ResultSet);
  • DbUtils.close(Statement);
  • DbUtils.close(Connection);

APIDocs показывает все доступные методы.


Обновление

Вот пример:

import org.apache.commons.dbutils;


Connection conn;
try{
    conn = getConnection();
    //Do databasey stuff
} catch(Exception e){
    //throw a glorious exception....
} finally{
    DbUtils.closeQuietly(conn); //This hides the SQLException thrown by conn.close();
    //or 
    //DbUtils.close(conn);
}

Обновление: по предложению ArtB, если вы, наконец, закрываете ресурсы и соединения, а findBugs - наглость, вы можете добавить следующую аннотацию (поверх метода).

@edu.umd.cs.findbugs.annotations.SuppressWarnings("OBL_UNSATISFIED_OBLIGATION")
4 голосов
/ 09 декабря 2010

Да, есть лучший способ.

Создайте статический метод, который переносит закрытие в try / catch:

public class DatabaseUtils
{
    public static void close(Connection c)
    {
        try
        {
            if (c != null)
            {
                c.close();
            }
        }
        catch (SQLException e)
        {
            // print or log stack trace
        }
    }

    // same for Statement and ResultSet
}
1 голос
/ 09 декабря 2010

Да, вы должны инкапсулировать ваше закрытие в блоке try, но есть более умный способ.

try {
    Connection c = getConnection();
    try {
        //do stuff
    } finally {
        c.close();
    }
} catch (SQLException e) {
    //Catch exceptions
}
0 голосов
/ 14 мая 2013

Вы можете избежать всего этого, используя что-то вроде Spring JDBCTemplate, которое правильно инкапсулирует всю логику открытия / закрытия для вас, упрощает ваш код, делает его чище и легче для чтения (а также с большей вероятностью будет правильным).

Пример чтения некоторых столбцов из таблицы в список пар ключ-значение (да, некрасиво, но легко понять):

        List<Map<String, Object>> resultList = jdbcTemplate.query(query,
                new RowMapper<Map<String, Object>>() {
                    @Override
                    public Map<String, Object> mapRow(ResultSet rs,
                            int rownum) throws SQLException {
                        Map<String, Object> row = new HashMap<String, Object>();
                        int colIndex = 0;
                        row.put(CONTENTID_KEY, rs.getInt(++colIndex));
                        row.put(CONTENTTYPEID_KEY, rs.getInt(++colIndex));
                        row.put(DESCRIPTION_KEY, rs.getString(++colIndex));
                        row.put(CODE_KEY, rs.getString(++colIndex));
                        return row;
                    }
                });

Об обработке исключений см. spring jdbcTemplate, как перехватывать исключения?

0 голосов
/ 09 декабря 2010

На самом деле лучшего способа не существует, но если вы хотите быть уверенным в том, что вы все поймаете, измените ваш шаблон так:

Connection conn;
try{
    conn = getConnection();
    //Do databasey stuff
}catch(Exceptions that get thrown){
}finally{
    try {
       conn.close();
    }
    catch  (SQLException se) {
       log.error("database problems...");
       // do more stuff if you need to
    }
}
...