Ich habe eine Methode zum Abrufen von Benutzern aus einer Datenbank mit JDBC:
public List<User> getUser(int userId) {
String sql = "SELECT id, name FROM users WHERE id = ?";
List<User> users = new ArrayList<User>();
try {
Connection con = DriverManager.getConnection(myConnectionURL);
PreparedStatement ps = con.prepareStatement(sql);
ps.setInt(1, userId);
ResultSet rs = ps.executeQuery();
while(rs.next()) {
users.add(new User(rs.getInt("id"), rs.getString("name")));
}
rs.close();
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
return users;
}
Wie sollte ich Java 7 Try-with-Resources verwenden , um diesen Code zu verbessern?
Ich habe es mit dem folgenden Code versucht, aber er verwendet viele try
Blöcke und verbessert die Lesbarkeit nicht wesentlich. Soll ich anders verwenden try-with-resources
?
public List<User> getUser(int userId) {
String sql = "SELECT id, name FROM users WHERE id = ?";
List<User> users = new ArrayList<>();
try {
try (Connection con = DriverManager.getConnection(myConnectionURL);
PreparedStatement ps = con.prepareStatement(sql);) {
ps.setInt(1, userId);
try (ResultSet rs = ps.executeQuery();) {
while(rs.next()) {
users.add(new User(rs.getInt("id"), rs.getString("name")));
}
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return users;
}
java
jdbc
java-7
try-with-resources
Jonas
quelle
quelle
try (ResultSet rs = ps.executeQuery()) {
da ein ResultSet-Objekt automatisch von dem Statement-Objekt geschlossen wird, das es generiert hatConnection
,PreparedStatement
undResultSet
auch. Kein Grund, dies nicht wirklich zu tun, da das Ausprobieren mit Ressourcen es so einfach macht und unseren Code in Bezug auf unsere Absichten selbstdokumentierender macht.Antworten:
In Ihrem Beispiel ist der äußere Versuch nicht erforderlich, sodass Sie mindestens von 3 auf 2 sinken können und auch nicht
;
am Ende der Ressourcenliste schließen müssen. Der Vorteil der Verwendung von zwei Try-Blöcken besteht darin, dass der gesamte Code im Voraus vorhanden ist, sodass Sie nicht auf eine separate Methode verweisen müssen:quelle
Connection::setAutoCommit
? Ein solcher Anruf isttry
zwischen demcon =
und nicht zulässigps =
. Wenn Sie eine Verbindung von einer DataSource abrufen, die möglicherweise mit einem Verbindungspool gesichert ist, können wir nicht davon ausgehen, wie autoCommit festgelegt ist.DriverManager.getConnection(myConnectionURL)
in eine Methode wechseln , die auch das AutoCommit-Flag setzt und die Verbindung zurückgibt (oder es in der Entsprechung dercreatePreparedStatement
Methode im vorhergehenden Beispiel setzen ...)DataSource
wo diegetConnection
Methode funktioniert, stellen Sie die Verbindung her, konfigurieren Sie sie nach Bedarf und geben Sie die Verbindung weiter.Mir ist klar, dass dies vor langer Zeit beantwortet wurde, aber ich möchte einen zusätzlichen Ansatz vorschlagen, der den verschachtelten Doppelblock "Versuch mit Ressourcen" vermeidet.
quelle
createPreparedStatement
ist unsicher, unabhängig davon, wie Sie ihn verwenden. Um dies zu beheben, müssten Sie einen try-catch um setInt (...) hinzufügen, einen abfangenSQLException
und in diesem Fall ps.close () aufrufen und die Ausnahme erneut auslösen. Dies würde jedoch zu einem Code führen, der fast so lang und unelegant ist wie der Code, den das OP verbessern wollte.Hier ist eine kurze Möglichkeit, Lambdas und JDK 8 Supplier zu verwenden, um alles in den äußeren Versuch zu integrieren:
quelle
Was ist mit dem Erstellen einer zusätzlichen Wrapper-Klasse?
Anschließend können Sie in der aufrufenden Klasse die prepareStatement-Methode wie folgt implementieren:
quelle
Wie andere gesagt haben, ist Ihr Code grundsätzlich korrekt, obwohl der äußere
try
nicht benötigt wird. Hier noch ein paar Gedanken.DataSource
Andere Antworten hier sind richtig und gut, wie die akzeptierte Antwort von bpgergo. Aber keine der Shows zeigt die Verwendung von
DataSource
, allgemein empfohlen gegenüber der VerwendungDriverManager
in modernem Java.Der Vollständigkeit halber finden Sie hier ein vollständiges Beispiel, das das aktuelle Datum vom Datenbankserver abruft. Die hier verwendete Datenbank ist Postgres . Jede andere Datenbank würde ähnlich funktionieren. Sie würden die Verwendung von
org.postgresql.ds.PGSimpleDataSource
durch eine Implementierung ersetzen, dieDataSource
Ihrer Datenbank entspricht. Eine Implementierung wird wahrscheinlich von Ihrem bestimmten Treiber oder Verbindungspool bereitgestellt, wenn Sie diesen Weg gehen.Eine
DataSource
Implementierung muss nicht geschlossen werden, da sie niemals „geöffnet“ wird. ADataSource
ist keine Ressource, ist nicht mit der Datenbank verbunden und enthält daher weder Netzwerkverbindungen noch Ressourcen auf dem Datenbankserver. ADataSource
sind lediglich Informationen, die beim Herstellen einer Verbindung zur Datenbank benötigt werden, mit dem Netzwerknamen oder der Netzwerkadresse des Datenbankservers, dem Benutzernamen, dem Benutzerkennwort und verschiedenen Optionen, die angegeben werden sollen, wenn eine Verbindung hergestellt wird. IhrDataSource
Implementierungsobjekt wird also nicht in die Klammern für den Versuch mit Ressourcen eingefügt.Verschachtelter Versuch mit Ressourcen
Ihr Code verwendet verschachtelte Try-with-Resources-Anweisungen ordnungsgemäß.
Beachten Sie im folgenden Beispielcode, dass wir die Try-with-Resources-Syntax auch zweimal verwenden , wobei eine in die andere verschachtelt ist. Das Äußere
try
definiert zwei Ressourcen:Connection
undPreparedStatement
. Das Inneretry
definiert dieResultSet
Ressource. Dies ist eine gängige Codestruktur.Wenn eine Ausnahme von der inneren ausgelöst und dort nicht abgefangen wird, wird die
ResultSet
Ressource automatisch geschlossen (falls vorhanden, ist sie nicht null). DanachPreparedStatement
wird das geschlossen und zuletzt dasConnection
geschlossen. Ressourcen werden automatisch in umgekehrter Reihenfolge geschlossen, in der sie in den Anweisungen zum Ausprobieren mit Ressourcen deklariert wurden.Der Beispielcode hier ist zu simpel. Wie geschrieben, kann es mit einer einzelnen Try-with-Resources-Anweisung ausgeführt werden. Aber in einer echten Arbeit werden Sie wahrscheinlich mehr Arbeit zwischen den verschachtelten Anrufpaaren
try
erledigen. Beispielsweise extrahieren Sie möglicherweise Werte von Ihrer Benutzeroberfläche oder einem POJO und übergeben diese dann, um?
Platzhalter in Ihrem SQL über Aufrufe vonPreparedStatement::set…
Methoden zu erfüllen .Syntaxnotizen
Nachfolgendes Semikolon
Beachten Sie, dass das Semikolon hinter der letzten Ressourcenanweisung in den Klammern des Versuchs mit Ressourcen optional ist. Ich nehme es aus zwei Gründen in meine eigene Arbeit auf: Konsistenz und es sieht vollständig aus und erleichtert das Kopieren und Einfügen einer Mischung von Zeilen, ohne sich um Semikolons am Zeilenende kümmern zu müssen. Ihre IDE kennzeichnet das letzte Semikolon möglicherweise als überflüssig, aber es schadet nicht, es zu verlassen.
Java 9 - Verwenden Sie vorhandene Variablen in Try-with-Resources
Neu in Java 9 ist eine Erweiterung der Syntax zum Ausprobieren von Ressourcen. Wir können jetzt die Ressourcen außerhalb der Klammern der
try
Anweisung deklarieren und füllen . Ich habe dies noch nicht für JDBC-Ressourcen nützlich gefunden, aber denken Sie bei Ihrer eigenen Arbeit daran.ResultSet
sollte sich schließen, darf aber nichtIn einer idealen Welt
ResultSet
würde sich das schließen, wie die Dokumentation verspricht:Leider haben in der Vergangenheit einige JDBC-Fahrer dieses Versprechen nicht erfüllt. Viele JDBC - Programmierer gelernt explizit schließen alle JDBC - Ressourcen , einschließlich Als Ergebnis
Connection
,PreparedStatement
undResultSet
auch. Die moderne Try-with-Resources-Syntax hat dies einfacher und mit kompakterem Code gemacht. Beachten Sie, dass sich das Java-Team die Mühe gemacht hat,ResultSet
als zu markierenAutoCloseable
, und ich schlage vor, dass wir davon Gebrauch machen. Durch die Verwendung eines Try-with-Resources für alle Ihre JDBC-Ressourcen wird Ihr Code in Bezug auf Ihre Absichten selbstdokumentierender.Codebeispiel
quelle