ResultSet is closed tritt bei JSF aber nicht bei einer Java-Applikation auf

Holy Diver

Mitglied
Bin mir nicht ganz sicher ob das jetzt der richtige Bereich ist da der Fehler nur bei einer JSF-Anwendung auftritt.
Jedes Mal wenn ich die Methode getSpecialSettings in einer JSF-Anwendung aufrufe führt dies zu
der SQL-Exception: Operation not allowed after ResultSet closed.

Führe ich folgende Java-Applikation aus kommt es aber zu keinem Fehler:
Java:
public static void main(String[] args) {
		LinkedList<Integer> n=new LinkedList<Integer>();n.add(798);
		LinkedList<specialsetting> s=DAO.getInstance().getSpecialSettings(n);
		s=DAO.getInstance().getSpecialSettings(n);
		DAO.getInstance().getClasses();
		s=DAO.getInstance().getSpecialSettings(n);
	}
getSpecialSettings:
Java:
public LinkedList<specialsetting> getSpecialSettings(LinkedList<Integer> IDs) {
		
             ........
		// Get a Statement:
		Statement stmt = pool.checkOut();
		
		try {
			ResultSet res = stmt.executeQuery(Query);
			....
			int ID;
			String sd_name,desc;
			while(res.next()){//Nach einen Durchlauf tritt hier der Fehler auf
				ID=res.getInt("ID");
				sd_name=res.getString("sd_name");
				desc=res.getString("description");
				
				........

				System.out.println("res "+res.isClosed());
				System.out.println("stmt " +stmt.isClosed());
			}//while
			.....	
		} catch (SQLException e) {
			e.printStackTrace();
		}
		// Return the Statement:
	    pool.checkIn(stmt);
		return specialsettings;
	}
Ausgabe:res true
stmt false
java.sql.SQLException: Operation not allowed after ResultSet closed

Der Pool gibt meinem Erachten kein Statement zweimal zurück, wenn er dies machen würde, gäbe es ja auch bei der Java-Applikation einen Fehler.
Ich benutze mysql-connector-java-5.1.18 und einen Tomcat v6.

Würde mich über Lösungsvorschläge oder über Vermutungen zur Ursache freuen.
 
> Der Pool gibt meinem Erachten kein Statement zweimal zurück

Tipp: erachte nicht sonder prüfe und wisse dann,
gibt von den ResultSets den HashCode aus, oder speichere sie temporär in Variablen und vergleiche sie mit ==,
oder wrappe alle Statements in eigenen Klassen und gib ihnen eindeutige Nummern im Konstruktor

ohne den Pool ist jedenfalls keine gute Aussage zu treffen,
wird dort jemals close() ausgeführt? wenn in deinem Code, dann logge auch das, wieder mit Hashcode/ == / Nummer

checkOut/ checkIn soll gleichzeitige Verwendung vermeiden?

logge ob bei JSF die Aufrufe von verschiedenen Threads gleichzeitig kommen
(Beginn, Ende loggen, Thread.getCurrentThread() für den Ausführer usw.,
die Parameter-Ids sind auch sicher gleich und haben keinen Einfluss wie Exception bei der Query oder so?)
 
Zuletzt bearbeitet von einem Moderator:
Deine Statement Pool Implementierung ist wohl fehlerhaft bzw. vom Grundkonzept falsch, IMHO poolt man keine Statements sondern Connections, jeder moderne JDBC Treiber bringt einen ConnectionPool mit.
 
> Der Pool gibt meinem Erachten kein Statement zweimal zurück

Tipp: erachte nicht sonder prüfe und wisse dann,

wird dort jemals close() ausgeführt?
checkOut/ checkIn soll gleichzeitige Verwendung vermeiden?
Sollten eigentlich schon dürfte aber nicht ganz funktionieren.
res.close() wird nirgends aufgerufen(wurde alles auskommentiert)
Bis zu folgenden Punkt wird immer ein checkOut und als nächstes ein CheckIN(es war immer nur ein Statement im Umlauf)

Ausgabe:
SpecialSettingsBean created!
Thread[http-8080-2,5,main] checkOut 1
Thread[http-8080-2,5,main] checkOut 1
Thread[http-8080-2,5,main] checkIn 1
res true
exstmt.stmt false
java.sql.SQLException: Operation not allowed after ResultSet closed

>
die Parameter-Ids sind auch sicher gleich und haben keinen Einfluss wie Exception bei der Query oder so?)
Ich habe mir den Parameter bei getSpecialSettings ausgegeben lassen und ihn bei der Java-Applikation verwendet, also diese sind sicher gleich.
Java:
public synchronized ExtendedStatement checkOut() {
		Statement stmt;
		ExtendedStatement exstmt;
		if (unlocked.size() > 0) {
			for(int i=0;i<unlocked.size();i++){
				stmt=unlocked.get(i).stmt;
				exstmt=unlocked.get(i);
					if (validate(stmt)) {
						unlocked.remove(stmt);
						locked.add(exstmt);
						System.out.println("checkOut"+exstmt.ID);
						return (exstmt);
					} else {
						// object failed validation
						unlocked.remove(exstmt);
						expire(stmt);
						i--;
						stmt = null;
						exstmt=null;
					}
			}
		}
		exstmt = create();
		locked.add(exstmt);
		System.out.println("checkOut"+exstmt.ID);
		return (exstmt);
	}
public synchronized void checkIn(ExtendedStatement stmt) {
		locked.remove(stmt);
		//unlocked.put(stmt, System.currentTimeMillis());
		System.out.println("checkIn"+stmt.ID);
		unlocked.add(stmt);
	}

 protected ExtendedStatement create() {
	    try {
	    	if(conn.isClosed()){
	    		NewConn();//Erzeugen der Connection
	    		}
	    	nrofstmt++;
	    	ExtendedStatement exstmt=new ExtendedStatement(conn.createStatement(),nrofstmt);
	    	return (exstmt);
	    } catch (SQLException e) {
	      e.printStackTrace();
	      return (null);
	    }
	  }

Deine Statement Pool Implementierung ist wohl fehlerhaft bzw. vom Grundkonzept falsch, IMHO poolt man keine Statements sondern Connections, jeder moderne JDBC Treiber bringt einen ConnectionPool mit.
Der Pool soll verhindern, dass die Statments immer neu erzeugt werden müssen und soll somit die Performance verbessern. Der Pool ist allerdings eine Vorgabe für mich.
 
Der Pool soll verhindern, dass die Statments immer neu erzeugt werden müssen und soll somit die Performance verbessern. Der Pool ist allerdings eine Vorgabe für mich.
Hört sich ehrlich gesagt sehr wirr an...
Gibt es Beweise dafür dass es dann schneller geht?

Ein ResultSet gehört zu einem Statement und dieses wiederrum zu einer Connection.
Connection wird geschlossen -> Statement wird geschlossen -> ResultSet wird geschlossen

Wie gesagt, halte das Poolen von Statements wie hier für grundsätzlich falsch.
 
oha, da habe ich in meinen Posts ja einiges durcheinandergebracht,
im Pool sind die Statements, und die sind ja (hier) nie geschlossen, habe dein Ausgabe-Log falsch interpretiert,
dann muss dazu ja auch nicht wirklich was geprüft werden wie HashCode-Vergleich,
obwohl trotzdem durchaus interessant sein kann, ob ein Statement wiederverwendet wird

eigentlich wollte ich dazu ja fragen ob die Statements geschlossen werden, an die ResultSets hatte ich gar nicht gedacht,
auch als Text verwechselt in meinem Posting

jetzt schreibst du
> res.close() wird nirgends aufgerufen(wurde alles auskommentiert)
das ist ja auch nicht so lustig, ResultSets sollten schon geschlossen werden, am Ende der Methode,

ist das ganze eigentlich reproduzierbar oder zufällig?
jetzt aufs ResultSet konzentriert: logge von Anfang an, von der Query, bis in die Schleife in jedem Schleifendurchlauf
und zu deiner schon vorhandenen Ausgabe, wann ist das ResultSet offen, wann erstmals geschlossen?
direkt nach executeQuery() doch sicher noch offen oder auch schon zu?
danach zu einem festen reproduzierbaren Zeitpunkt (wann?) oder wechselnd?

gerade wechselnd würde für einen anderen Thread sprechen, denn die Wiederverwendung des Statements,
eine neue Query mit neuen ResultSet, schließt das erste ziemlich sicher, wenn ich mich nicht komplett irre

das Log
> SpecialSettingsBean created!
> Thread[http-8080-2,5,main] checkOut 1
> Thread[http-8080-2,5,main] checkOut 1
> Thread[http-8080-2,5,main] checkIn 1

spricht ja auch dafür, dass das Statement 1 zweimal gleichzeitig herausgegeben wird, oder?
das wäre dann ja der Fehler, obwohl es nicht nach verschiedenen Threads aussieht,
kann es sein dass ein Thread verschachtelt mehrmals Statements anfordert?
widerspricht wiederum der funktionierenden main-Variante..

lieber doch mehrere Threads vermuten, merke dir diese auch irgendwo, z.B. bei jedem checkOut in einer Liste,
dazu ==-Vergleich mit den vorhandenen, ausgeben

aber letztlich kann das auch egal sein, zweimal
> Thread[http-8080-2,5,main] checkOut 1
> Thread[http-8080-2,5,main] checkOut 1
ist doch in jedem Fall ein Fehler, oder?

ich kann in dem Code zum Pool vorerst nicht so viel erkennen
 
Zuletzt bearbeitet von einem Moderator:
Gibt es Beweise dafür dass es dann schneller geht?
Ich kenne keine,allerdings habe ich mich bis jetzt eher wenig mit Performance beschäftigt
Ein ResultSet gehört zu einem Statement und dieses wiederrum zu einer Connection.
Connection wird geschlossen -> Statement wird geschlossen -> ResultSet wird geschlossen
Das kann hier allerdings nicht der Grund für den Fehler sein,da das Statement zum Zeitpunkt des Fehlers noch offen ist.


jetzt schreibst du
> res.close() wird nirgends aufgerufen(wurde alles auskommentiert)
das ist ja auch nicht so lustig, ResultSets sollten schon geschlossen werden, am Ende der Methode,
Grundsätlich passiert dass bei mir immer vor dem zurückgeben,allerdings wurde dies im Laufe der Fehlersuche auskommentiert.
ist das ganze eigentlich reproduzierbar oder zufällig?
Der Fehler tritt immer auf,wenn ich die Methode mit einer ID,welche in der DB vorhanden ist,aufrufe.
jetzt aufs ResultSet konzentriert: logge von Anfang an, von der Query, bis in die Schleife in jedem Schleifendurchlauf
und zu deiner schon vorhandenen Ausgabe, wann ist das ResultSet offen, wann erstmals geschlossen?
direkt nach executeQuery() doch sicher noch offen oder auch schon zu?
Direkt nach dem execute müsste es noch offen sein,sonst würde die Schleife nicht ausgeführt.
danach zu einem festen reproduzierbaren Zeitpunkt (wann?) oder wechselnd?

gerade wechselnd würde für einen anderen Thread sprechen, denn die Wiederverwendung des Statements,
eine neue Query mit neuen ResultSet, schließt das erste ziemlich sicher, wenn ich mich nicht komplett irre
Hier irrst du dich sicher nicht,denn Fehler hatte ich vor nicht ganz so langer Zeit.
das Log
> SpecialSettingsBean created!
> Thread[http-8080-2,5,main] checkOut 1
> Thread[http-8080-2,5,main] checkOut 1
> Thread[http-8080-2,5,main] checkIn 1

spricht ja auch dafür, dass das Statement 1 zweimal gleichzeitig herausgegeben wird, oder?
das wäre dann ja der Fehler, obwohl es nicht nach verschiedenen Threads aussieht,
kann es sein dass ein Thread verschachtelt mehrmals Statements anfordert?
widerspricht wiederum der funktionierenden main-Variante..
Schaut für mich auch danach aus,dass ein Statment zweimal zurückgegeben wird.
Allerdings sollte das mit den Listen und dem synchronized verhindert werden.

Es gibt Methoden die mehr als ein Statment benutzen oder eine andere Methode aufrufen(die wiederum ein Statment) benutzen,während diese noch ein stmt aus dem Pool haben.
lieber doch mehrere Threads vermuten, merke dir diese auch irgendwo, z.B. bei jedem checkOut in einer Liste,
dazu ==-Vergleich mit den vorhandenen, ausgeben
Ich habe jetzt bei jedem System.out.printl("checkOut"...) ein threads.add(Thread.currentThread().hashCode());.
//LinkedList<Integer> threads=new LinkedList<Integer>();
Beim CheckIn threads.removeFirstOccurrence(Thread.currentThread().hashCode()); und am Anfang von CheckOut:if(threads.contains((Thread.currentThread().hashCode()))){
System.out.println("Thread gets multiple stmt");}
Hoffe das war so gemeint.

aber letztlich kann das auch egal sein, zweimal
> Thread[http-8080-2,5,main] checkOut 1
> Thread[http-8080-2,5,main] checkOut 1
ist doch in jedem Fall ein Fehler, oder?
Wenn es zweimal das gleiche Statment ist,ist es sicher ein Fehler.

Log:
SpecialSettingsBean created!
Thread[http-8080-1,5,main] checkOut 1
res1 false
res2 false
res3 false
res3.0.1 false
Thread gets multiple stmt
Thread[http-8080-1,5,main] checkOut 1
Thread[http-8080-1,5,main] checkIn 1
res3.1 true
res4 true
exstmt.stmt false
java.sql.SQLException: Operation not allowed after ResultSet closed

Der Fehler titt also zwischen 3.01 und 3.1 auf
Java:
....
System.out.println("res3 "+res.isClosed());
				if(specialsettings.isEmpty() && specials==null){
					specials=new specialsetting();
                                        //Wertzuweisungen
					specials.ID=ID;
					.......
                                        System.out.println("res3.0.1 "+res.isClosed());
					specials.extendRoomlist(upis, getRoomList(re_ID,upis));
					System.out.println("res3.1 "+res.isClosed());
				}
...
private LinkedList<Room> getRoomList(int re_ID,String upis)
	{
		String Query="..."
		// Get a Statement:
		ExtendedStatement exstmt = pool.checkOut();
		LinkedList<Room> roomlist = new LinkedList<Room>();
		
		try {
			ResultSet res=exstmt.stmt.executeQuery(Query);
			while(res.next()){
				roomlist.add(new Room(res.getString("room_ID"),res.getInt("size")));
			}
			//res.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
	    pool.checkIn(exstmt);
	    return roomlist;
	}
Der Fehler dürfte wirklich darin liegen, dass getRoomList(..) ein bereits verwendetes Statemant bekommt. Ich kann aber nicht nachvolzihen warum der Pool ein Statemant zweimal vergibt.
 
schöne Debug-Log-Ausgaben, sieht man seltener als ich sie fordere 😉
warum machst du damit im Pool nicht weiter?
habe ihn mir jetzt erst angeschaut, soviel du davon gepostet hast,
du läßt ja gar manche Variablen wie unlocked/ locked im Dunkeln, auch wenn es wohl Listen sind,

der Code ist aber überschaubar mit nur wenigen Schleifen, add/ remove, das kann man doch im Detail anschauen,
wie groß ist die Liste, welche Elemente werden geprüft, warum gelten sie jeweils als ok oder nicht ok usw.,

der aktuelle Fehler scheint
> unlocked.remove(stmt);
zu sein, in der Liste ist doch stmt gar nicht drin sondern exstmt,
das exstmt bleibt so in unlocked und kann mehrfach zurückgegeben werden,

falls du diese Wrapper-Klasse erst auf meinen Vorschlag hin gebaut hast, bin ich wohl daran schuld und es mag der Original-Fehler immer noch irgendwo schlummern,
so wie es aktuell steht dürfte die main-Methode auch scheitern, oder?
denn dort wird ja genauso die Untermethode mit zweitem checkOut usw. gerufen
 
warum gelten sie jeweils als ok oder nicht ok usw.,
Die Methoden hatte ich nicht gepostet, da sie ja nicht der Grund für eine doppelte Ausgabe sein kann.
[Java]
private LinkedList<ExtendedStatement> locked;
private LinkedList<ExtendedStatement> unlocked;
.....
public void expire(Statement stmt) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public boolean validate(Statement stmt) {
try {
return (!stmt.isClosed());
} catch (SQLException e) {
e.printStackTrace();
return (false);
}
}[/Java]
der aktuelle Fehler scheint
> unlocked.remove(stmt);
zu sein, in der Liste ist doch stmt gar nicht drin sondern exstmt,
das exstmt bleibt so in unlocked und kann mehrfach zurückgegeben werden,

falls du diese Wrapper-Klasse erst auf meinen Vorschlag hin gebaut hast, bin ich wohl daran schuld und es mag der Original-Fehler immer noch irgendwo schlummern,
so wie es aktuell steht dürfte die main-Methode auch scheitern, oder?
denn dort wird ja genauso die Untermethode mit zweitem checkOut usw. gerufen
Ja die main funktionierte auch nicht mehr.
Die Wrapper-Klasse entstand erst auf den Vorschlag hin,aber wenn ich nun unlocked.remove() mit exstmt aufrufe tritt das ResultSet nicht mehr auf, obwohl das ja nicht der Grund für den vorherigen Fehler sein kann und auch wenn ich die ExtendedStatements mit normalen Statements austausche geht es auch.

Die einzige Änderung die mir einfällt wäre,dass ich bei
Java:
} else {
		// object failed validation
		unlocked.remove(stmt);
		expire(stmt);
		i--;
		stmt = null;
	}
das i--; hinzugefügt hatte. Dies würde aber nur dazu führen, dass ein Statement übersprungen würde und damit eines erzeugt wird obwohl sich ein anderes noch in Unlocked befindet.
 

Neue Themen


Zurück
Oben