2010-03-02 10 views
21

Podczas korzystania z PreparedStatement w JDBC, należy najpierw zamknąć PreparedStatement lub Connection? Właśnie zobaczyłem próbkę kodu, w której Connection jest zamknięty, ale wydaje mi się bardziej logiczne, aby najpierw zamknąć PreparedStatement.Co powinienem najpierw zamknąć, PreparedStatement lub połączenie?

Czy istnieje standardowy, akceptowany sposób na zrobienie tego? Czy to ma znaczenie? Czy zamknięcie Connection powoduje również zamknięcie PreparedStatement, ponieważ PreparedStatement jest bezpośrednio związane z obiektem Connection?

+1

Gdzie to widziałeś? – BalusC

+0

Chociaż zgodnie ze specyfikacją, oświadczenie powinno zostać zamknięte, gdy połączenie jest zamknięte, sterowniki JDBC mają problemy z tym, więc dobrym zwyczajem jest jawne zamknięcie instrukcji (i zestawu wyników). – Yishai

+0

Zamknij rzeczy w odwrotnej kolejności, kiedy je otworzyłeś. Wszystkie rzeczy. – EJP

Odpowiedz

36

Oświadczenie. Spodziewam się, aby zamknąć (w kolejności)

  1. zestaw wyników
  2. oświadczenie
  3. połączenie

(i sprawdzić null po drodze!)

tj zamknij w w odwrotnej kolejności kolejność otwierania.

Jeśli użyjesz Spring JdbcTemplate (lub podobnej), to zaopiekuje się nim dla ciebie. Alternatywnie możesz użyć Apache Commons DbUtils i DbUtils.close() lub DbUtils.closeQuietly().

+1

Rzeczywiście. Niektóre sterowniki JDBC rzucają wyjątek podczas zamykania zestawu wyników lub instrukcji po zamknięciu połączenia. – Yishai

+11

Zgadza się. Do rzeczy: zamknij * zasoby * w ** odwróconej kolejności **, gdy je nabyłeś. – BalusC

7

Następujące procedury należy zrobić (w kolejności)

  • ResultSet
  • PreparedStatement
  • Connection.

Zaleca się również zamknięcie wszystkich obiektów związanych z JDBC w pobliżu, aby zagwarantować zamknięcie.

//Do the following when dealing with JDBC. This is how I've implemented my JDBC transactions through DAO.... 

Connection conn = null; 
PreparedStatement ps = null; 
ResultSet rs = null; 

try { 
    conn = .... 
    ps = conn.prepareStatement(...); 

    //Populate PreparedStatement 
    rs = ps.executeQuery(); 

} catch (/*All relevant exceptions such as SQLException*/Exception e) { 
    logger.error("Damn, stupid exception: " , e); 
} finally { 
if (rs != null) { 
      try { 
       rs.close(); 
       rs = null; 
      } catch (SQLException e) { 
       logger.error(e.getMessage(), e.fillInStackTrace()); 
      } 
     } 

     if (ps != null) { 
      try { 
       ps.close(); 
       ps = null; 
      } catch (SQLException e) { 
       logger.error(e.getMessage(), e.fillInStackTrace()); 
      } 
     } 

     try { 
      if (conn!= null && !conn.isClosed()){ 
       if (!conn.getAutoCommit()) { 
        conn.commit(); 
        conn.setAutoCommit(true); 
       } 
       conn.close(); 
       conn= null; 
      } 
     } catch (SQLException sqle) { 
      logger.error(sqle.getMessage(), sqle.fillInStackTrace()); 
     } 
} 

Widać mam sprawdzić czy moje przedmioty tracą połączenie, sprawdź pierwszy jeśli połączenie nie jest autocommited. Wiele osób nie sprawdza tego i zdaje sobie sprawę, że transakcja nie została przekazana do DB.

+5

Wszystko to ostatecznie powinno zostać skondensowane na metodę użyteczności (na przykład 'DBUtils.close (rs, ps, conn);'). Również porady dotyczące autocommit zależą od sytuacji. Czasami, gdy jest wyjątek, nie chcesz w ogóle angażować się. Również wysiłek polegający na jawnym ustawieniu odniesienia do wartości null jest prawie zawsze niepotrzebny, ponieważ zostanie on usunięty z pamięci, gdy metoda zostanie zakończona, co, miejmy nadzieję, wkrótce nastąpi później, w przeciwnym razie metoda będzie prawdopodobnie zbyt długa. – Yishai

+0

@Yaiai - dzięki, zastanawiałem się nad tym. – froadie

+0

@ Yishai, tak, zapomniałem wspomnieć, że jeśli są wyjątki i autocommit jest wyłączony, możesz cofnąć ... Dzięki za pokazanie tego. –