Frage

Betrachten Sie den Code ein:

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();
}

Das oben nicht kompilieren, weil beide PreparedStatement.close() und ResultSet.close() ein java.sql.SQLException werfen. So füge ich einen try / catch-Block in den finally? Oder die Close-Anweisungen in die try-Klausel bewegen? Oder gerade nicht in der Nähe stören anrufen?

War es hilfreich?

Lösung

Datei-I / O, füge ich im Allgemeinen einen try / catch um die schließlich zu blockieren. Sie müssen jedoch vorsichtig sein, keine Ausnahmen von dem finally-Block zu werfen, da sie die ursprüngliche Ausnahme verursachen werden (falls vorhanden) verloren.

dieser Artikel für ein spezifischeres Beispiel der Datenbankverbindung Schließen Siehe.

Andere Tipps

In Java 7, sollten Sie sie nicht explizit schließen, aber benutzen automatische Ressourcenmanagement dass Ressourcen, um sicherzustellen, geschlossen und Ausnahmen in geeigneter Weise behandelt werden. Ausnahmebehandlung funktioniert wie folgt:

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

Wir hoffen, die Sinn macht. In ermöglicht es ziemlich Code wie folgt:

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);
  }
}

Vor Java 7, ist es am besten verschachtelt schließlich Blöcke zu verwenden, anstatt Referenzen für null zu testen.

Das Beispiel zeige ich werde mit der tiefen Verschachtelung hässlich aussehen könnte, aber in der Praxis gut gestalteter Code ist wahrscheinlich keine Verbindung, Anweisung gehen zu schaffen, und führt alle in der gleichen Methode; Oft beinhaltet jede Ebene der Verschachtelung einer Ressource zu einer anderen Methode übergeben, die sie als einer Fabrik für eine andere Ressource verwendet. Mit diesem Ansatz Ausnahmen von einer close() eine Ausnahme von der Innenseite des try Block maskieren. Das kann überwunden werden, aber es ergibt sich noch unordentlich Code und erfordert eine individuelle Ausnahmeklasse, die die „unterdrückt“ Ausnahme stellt Verkettungs in Java 7.

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

Wenn Sie wirklich Ihre eigene jdbc Hand-rolling wird es definitiv chaotisch. Die close () in der muss schließlich mit seinem eigenen Versuch fängt eingewickelt werden, die, zumindest, hässlich ist. Sie können die Nähe nicht überspringen, obwohl werden die Ressourcen gelöscht werden, wenn die Verbindung geschlossen ist (die vielleicht nicht sofort, wenn Sie einen Pool verwenden). Eigentlich einer der wichtigsten Verkaufsargumente für einen Rahmen (z.B. Hibernate) Ihren DB-Zugriff zu verwalten, ist die Verbindung zu verwalten und Ergebnismenge der Handhabung, so dass Sie nicht in die Nähe vergessen.

Sie können zumindest etwas Einfaches wie das, was tun, das Chaos verbirgt, und garantiert, dass Sie nicht vergessen, etwas.

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);
        }
    }

}

und dann

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

Vergeuden Sie nicht Ihre Zeit Low-Level-Exception Management Codierung verwenden, um einen höheren-Level-API wie Spring-JDBC oder einen benutzerdefinierten Wrapper um Verbindung / Statement / rs Objekte, den chaotischen try-catch geritten Code zu verbergen.

Beachten Sie auch:

„Wenn ein Statement-Objekt geschlossen wird, sein aktuelles ResultSet-Objekt, falls vorhanden, ist ebenfalls geschlossen.“

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

Es sollte nur das PreparedStatement in einem endlich zu schließen ausreichend sein, und nur dann, wenn es nicht bereits geschlossen ist. Wenn Sie wollen, obwohl wirklich besonders sein, schließen Sie das ResultSet FIRST, nicht nach dem PreparedStatement Schließen (Schließen sie nach, wie einige der Beispiele hier sollte eigentlich eine Ausnahme garantieren, da es bereits geschlossen ist).

ich in der Regel ein Dienstprogramm Methode haben, die Dinge wie diese schließen können, einschließlich kümmert nicht zu versuchen, alles mit einem NULL-Verweis zu tun.

Normalerweise, wenn close() eine Ausnahme auslöst mich nicht wirklich kümmern, so dass ich lüge nur die Ausnahme und schlucken - aber eine andere Alternative wäre es in ein RuntimeException zu konvertieren. So oder so, ich empfehle es in einer Dienstprogramm-Methode zu tun, die einfach zu nennen, ist, wie Sie auch dieses in vielen Orten tun müssen.

Beachten Sie, dass Ihre aktuelle Lösung nicht die ResultSet schließen, wenn das PreparedStatement schließt nicht -. Es ist besser verschachtelt schließlich Blöcke zu verwenden,

Wenn Ihr verwenden Java 7 Sie die Verbesserungen in der Ausnahmebehandlungsmechanismen in diesen Klassen verwenden können, die AutoCloseable (dh PreparedStatement, Resultset)

Sie können auch diese Frage interessant finden: Schließen ResultSet in Java 7

Ich weiß, dass dies eine alte Frage, aber nur für den Fall jemand die Antwort suchen, Java hat nun die Try-mit-resouce Lösung.

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

Sie nicht auslassen Aufruf schließen. Es kann zu Problemen führen.

Ich ziehe das Hinzufügen try / catch-Block zu dem schließlich.

Wahrscheinlich ein alter (aber einfach) Weg, um Dinge zu tun, aber es funktioniert immer noch:

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();
        }               
    }
}

Aufbauend auf @ Erickson Antwort, warum nicht tut es nur in einem try Block wie das?

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);
  }
}

Beachten Sie, dass Sie nicht über die ResultSet Objekt innerhalb des try Block erstellen müssen als ResultSet die automatisch geschlossen werden, wenn das PreparedStatement Objekt geschlossen wird.

  

Ein ResultSet Objekt wird automatisch geschlossen, wenn das Statement-Objekt   , die erzeugt er geschlossen ist, erneut ausgeführt, oder verwendet, um die nächste zurückzuholen   ergeben sich aus einer Folge von mehreren Ergebnissen.

Referenz: https://docs.oracle .com / JavaSE / 7 / docs / api / java / sql / ResultSet.html

Fokus finally,

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

Ich glaube, Sie 2 Punkte ändern haben.

Verwenden Sie zuerst versuchen und wieder in fainlly Klausel zu fangen.

Zweitens, rs.close () vor ps.close tun ().

fly1997@naver.com

Ich benutze diese ..

finally
{
    if (ps != null) ps.close();
    if (rs != null) rs.close();
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top