Datenbankverbindungen schließen und somit wieder in den Connection Pool zurueck legen

Fasibio

Mitglied
Hallo,
ich hatte ein seltsames Problem, das ich zwar mittlerweille gelöst habe, jedoch nicht verstanden habe, wiso es überhaupt auftritt.

Ich habe ein Programm das über einen Tomcat Connection Pool Verbindungen mit der Datenbank aufbaut.
Dies funktionierte auch alles einwandfrei, jedoch bekame nach einer gewissen Anzahl keine neuen Verbindugen, da der Pool leer war.
Ich konnte es auf die Select Statements zurueckfuehren.
Dort habe ich es so realisiert, das eine Methode das Statement entgegennimmt und die Abfrage durchführt .
Als Return liefert es das ResultSet zurueck.
Java:
protected ResultSet getInfomation(String sql,Object... map) throws SQLException{
PreparedStatement query ;
try {
query = getNewConnection(true).prepareStatement(sql);//Liefert ein neue Connection aus dem Pool und aus dieser ein Statement
setPreparedElements(query, map);//Verbindet die Elemente in MAP mit dem Statement
log.debug(query);
ResultSet set = query.executeQuery();
return getDecodeResultSet(set);//Ein ResultSet Proxy (Da die Werte in der DB verschlüsselt sind) wird im Proxy die Methode getString verändert sonst nichts
} catch (SQLException e) {
log.error(e);
throw e;
}
}

Die eigentliche Methode verarbeitet das ResultSet und schließt über das ResultSet die Verbindung mit der Datenbank wie folgt:

Java:
ResultSet set = getInfomation("STATEMENT");
// Mach was mit set

set.getStatement().getConnection().close();
set.getStatement().close();
set.close();

Dies hat nicht funktioniert. Die Connection kam nicht zurueck in den Pool.
Erst als ich die in der Methode getInformation erstellten Objekte (Connection-Obj & Statement-Obj) geschlossen habe konnte er dies wieder zurueck in den Pool geben.

Nun meine Frage:

Warum funktioniert es, wenn ich die Objecte direkt schließe wo ist da der unterschied zu den relativen Objekten wenn ich das Statement und die Connection über das ResultSet besorge ?

Dazu muss ich jedoch noch sagen das es sich bei dem ResultSet um eine von mir entwickelte Proxy methode handelt. Jedoch ist nur die Methode getString verändert alles andere wird an das Ursprüngliche result weitergeleitet.

Hoffe ihr versteht was ich mein und könnt mir eine Antwort geben.
Danke für eure Hilfe.

Fasibio
 
Hi,

die Methode getNewConnection() liefert eine Referenz auf eine java.sql.Connection-Instanz zurück, auf der direkt die Methode prepareStatement() aufgerufen wird. Du speicherst die Referenz auf Connection jedoch nicht in einer Variable ab. Daher wird die Instanz direkt nach dem Aufruf von getNewConnection() dem GarbageCollector zum Aufräumen überlassen. Soviel zur technischen Theorie.

Dann rufst du auf der Connection close(), auf dem Statement close() und zuletzt auf ResultSet close() auf. Das ist eigentlich die falsche Reihenfolge. Die Resourcen müssen in der gegenteiligen Reihenfolge geschlossen werden, wie sie geöffnet werden.

1. ResultSet schließen
2. Statement schließen
3. Connection schließen.

Wenn du das alles auch noch innerhalb ein und des selben try-catch-Blocks machst (bei dem auch nicht geloggt wird, wenn ein Fehler auftritt), kann es passieren, dass keine der Aufrufe erfolgreich durch läuft.

Tipp: Wenn du Spring einsetzen würdest, könntest du dir einen TransactionManager einkonfigurieren und dann auf Transaktionsebene Connection vom Container abholen und wieder zurück gegen lassen. Dann müsstest du dich um den ConnectionPool nicht selbst kümmern sondern würdest Spring die ganze Arbeit überlassen. Noch besser wäre ein J2EE-Container wie Wildfly.
 
Ja ok falsche Reihenfolge <- Check
Das mit dem GC Versteh ich nicht so ganz da ja das Statement Object noch eine Referenz auf das Connection Obj hat und das ResultSet eine Referenz auf das Statment hat sollten ja alle Objekte sich noch im Zugriff befinden.

Zur Aussage:
Wenn du das alles auch noch innerhalb ein und des selben try-catch-Blocks machst (bei dem auch nicht geloggt wird, wenn ein Fehler auftritt), kann es passieren, dass keine der Aufrufe erfolgreich durch läuft.

Ja gut ich Logge ja im catch fall mit ....
Somit kann ich sicherstellen das kein Fehler aufgetreten ist... (Siehe catch im ersten Code Block)

Mich wundert ja das ich mit dem Referenzierten Statement und die Referenzierte Connection (Siehe zweiten Code Block) kein zurücklegen in den Connectionpool erfolgt.
Sondern es nur dann erfolgreich ist, wenn ich die ursprünglich erzeugten Objekt direkt schließe.

Gruß
Fabian
 
Schau halt mal, ob resultSet.getStatement().getConnection() wirklich das gleiche Objekt ist, das getNewConnection() zurück liefert. Das kannst du mittels Debugging oder via toString() (was die Objekt-Id zurück liefern sollte) raus bekommen. Wenn du mit einem Proxy arbeitest, bietet sich evtl. eine Objekt-Struktur an, in der sowohl das ResultSet, sowie das Statement als auch die Connection beinhaltet, so kannst du das jederzeit kontrolliert freigeben.
 

Neue Beiträge

Zurück