2015-06-12 2 views
2

Мне любопытно узнать о лучших практиках, когда дело доходит до взаимодействия с базой данных. Я использую шаблон, который, как я полагаю, обрабатывает, чтобы все соответствующие объекты были закрыты, когда я закончил с ними. Тем не менее, коллега недавно реорганизовал мой код с комментарием в соответствии с «тем, что мы всегда закрываем объекты базы данных». Мне нужно знать, если по какой-то причине один образец «лучше», чем другой. Является ли шаблон каким-то образом неправильным? Имеет ли один образец преимущества над другими?Каков предпочтительный метод обеспечения закрытия объектов базы данных?

Узор, который я следующее:

public void doStuff() { 
    try { 
     final Connection connection = this.getConnection(); 

     try { 
      final PreparedStatement ps = connection.prepareStatement("SELECT COLA, COLB FROM TBL WHERE COLC = ?"); 

      try { 
       ps.setString(1, "asdf"); 
       final ResultSet rs = ps.executeQuery(); 
       try { 
        // get data from rs 
       } finally { 
        rs.close(); 
       } 
      } finally { 
       ps.close(); 
      } 
     } finally { 
      connection.close(); 
     } 
    } catch (SQLException e) { 
     // do something with the error 
    } 
} 

Узор, что мой коллега доработан мой код:

public void doStuff() { 
    Connection connection = null; 
    PreparedStatement ps = null; 
    ResultSet rs = null; 
    try { 
     connection = this.getConnection(); 
     ps = connection.prepareStatement("SELECT COLA, COLB FROM TBL WHERE COLC = ?"); 
     ps.setString(1, "asdf"); 
     rs = ps.executeQuery(); 
     // get data from rs 
    } finally { 
     if (rs != null) { 
      try { 
       rs.close(); 
      } catch (SQLException e) { 
       // do something with the error 
      } 

     } 
     if (ps!= null) { 
      try { 
       ps.close(); 
      } catch (SQLException e) { 
       // do something with the error 
      } 
     } 
     if (connection != null) { 
      try { 
       connection.close(); 
      } catch (SQLException e) { 
       // do something with the error 
      } 
     } 

    } 
} 
+2

Вы правы на поиск снова, ваш путь также закрывает все. Я отозвал свой ответ :). Тем не менее, оба они уродливые.Если у вас есть java7, чем try -with-resources - это значительное улучшение! –

+0

@RobertMoskal не может спорить там! =) – GamerJosh

ответ

5

Если вы используете Java 6 или до, а затем использовать потому что его легче читать и поддерживать. Обратите внимание, что последнее можно улучшить с помощью некоторого рефакторинга для обработки громоздкого try-catch для каждого вызова метода close.

Если вы используете Java 7 или выше, а затем использовать try-with-resources:

try (Connection con = ...; 
    PreparedStatement pstmt = ...) { 
    pstmt.setXyz(...); 
    ResultSet rs = pstmt.executeQuery(); 
    //read data from resultset 
    //and then close it 
    rs.close(); 
} catch (Exception e) { 
    //handle the exception properly... 
} 

В случае, если вы хотите, чтобы убедиться, что о закрытии ResultSet, вы можете использовать вложенную try-with-resources:

try (Connection con = ...; 
    PreparedStatement pstmt = ...) { 
    pstmt.setXyz(...); 
    try(ResultSet rs = pstmt.executeQuery()) { 
     //read data from resultset 
    } 
} catch (Exception e) { 
    //handle the exception properly... 
} 
+0

* Зачем использовать последний? Что с ним делает лучше, чем первое? try-with-resource - отличный совет, хотя - спасибо! – GamerJosh

+1

Опубликован обновленный ... –

+0

Что делать, если из-за подключения выйдет exeption? –

1

Последнее легче читать; Глубокое гнездование трудно рассуждать.

Я предпочитаю безопасные обертки вокруг закрывающих объектов, например, они ничего не делают, если закрытие равно null. Это также упрощает чтение кода магистрали.

Ответ Луиджи, безусловно, имеет смысл с Java 7.

0

Часто проще и чище абстрагировать закрытие ресурсов базы данных выделенным объектом-менеджером, который будет содержать любые NPE и такие, которые могут быть выбраны.

Довольно хорошо написана одна существует в рамках проекта с открытым исходным кодом, OpenFire:

https://github.com/igniterealtime/Openfire/blob/master/src/java/org/jivesoftware/database/DbConnectionManager.java#L243

Sample вспомогательный метод из этого DbConnectionManager:

public static void closeResultSet(ResultSet rs) { 
    if (rs != null) { 
     try { 
       rs.close(); 
      } 
     catch (SQLException e) { 
      Log.error(e.getMessage(), e); 
     } 
    } 
} 

Так что в вашем finally блоке вы просто передайте свои ресурсы обратно своему менеджеру, и он обрабатывает уродливую логику для проверки нулей и исключений catch и т. д.

Как:

Connection con = null; 
PreparedStatement ps = null; 
ResultSet rs = null; 
try { 
    con = DbConnectionManager.getConnection(); 
    ps = con.prepareStatement(yourStatement); 
    rs = ps.executeQuery(); 
    if (rs != null) { 
     while (rs.next()) { 
      // do stuff 
     } 
    } 
} catch (SQLException e) { 
    LOG.error(e.getMessage(), e); 
} finally { 
    DbConnectionManager.closeConnection(rs, ps, con); 
} 
+1

В этом случае соединение не будет закрыто, и у вас будет утечка памяти. Если вы где-то храните «соединение», вы (несколько) попадете во вторую часть кода, предоставленную OP. –

+0

@LuiggiMendoza это был быстрый образец кода - не заслуживающий нисходящего. Обновлено, чтобы показать лучшую форму. Следует отметить, что это соединение происходит от менеджера пула, так как во избежание массовых накладных расходов при открытии нового соединения с базой данных при каждом вызове метода. – SnakeDoc

+1

Даже быстрый образец кода не должен быть грязным :) –

-5

Симуляция Defer заявление Гоу: D

try(Defer defer = new Defer()) 
{ 
    Connection connection = ...; 
    defer.add(connection::close); 

    .... 

    Path tmpFile = ...; 
    defer.add(()->Files.delete(tmpFile)); 

    .... 

} // Defer.close() => executing registered actions, from last to first 

Как Defer осуществляется оставляется в качестве упражнения для читателей :)

+0

Какое определение класса Defer в Java? Я не могу найти его в JDK. –

+0

@LuiggiMendoza - нет. это идея; реализация должна быть тривиальной. – ZhongYu

+2

Тогда это не правильный ответ. –