statement.executeQuery(sqlQuery) hängt

franzy

Aktives Mitglied
Guten Morgen,

wir haben folgendes Problem.
Wir haben eine JSF-Webapplikation in einem Tomcat 7 unter Java (build 1.6.0_18-b07) und einer MSSQL Express Datenbank am laufen, die wir selbst programmiert haben.
Grundsätzlich funktioniert die Anwendung auch, jedoch kommt es ab und zu mal vor, dass die Anwendung hängen bleibt. Das Logfile vom Tomcat und SQL Server gibt keine Auskunft über das hängenbleiben. Ich habe nun mal internsiver geschaut und merke dass die Anwendung in unserem DatenbankBean beim Befehl statement.executeQuery(sqlQuery) hängen bleibt. Darauf hin wollte ich auf die Tabelle in der Datenbank zugreifen mit einem Tool um zu schauen ob da was nicht stimmt. Dem war auch so, ihrgend wie scheint eine Sperre drauf zu sein, weil auch in dem Tool werden die Daten nicht geladen und die anfrage wird nicht abgeschlossen.

Ich zeig hier mal eine Select Methode die verwendet wird und eine Update Methode. Ich setzte das setAutoCommit(false). Evt. liegt es daran, dass sich die JDBC-Threads in die quere kommen und vor dem Fehler eiun Update gemacht wurde.

Java:
public List<Entity> readTable(String number) throws DatabaseReadDataException, DatabaseOpenConnectionException, DatabaseCloseConnectionException  {
	List<Entity> resultList = null;

	String sqlQuery = "SELECT ****";
	
	Statement statement = null;
	ResultSet resultSet = null;
	
	try {
		this.createConnection();
		
		statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
		resultSet = statement.executeQuery(sqlQuery); -> hier bleibt er hängen
		   
		resultSet.last();
		long rowCount = resultSet.getRow();

		if (rowCount != 0)
		{
			resultSet.beforeFirst();
			
			resultList = new ArrayList<Entity>();
			
			while(resultSet.next()){
				//resultset wird gelesen
			}
		}
		
		return resultList;
	} 
	catch (SQLException ex) {
		throw new DatabaseReadDataException(ex.getMessage());
	}    
	finally{
		try{
			if (resultSet != null) resultSet.close();
			if (statement != null) statement.close();

			this.closeConnection();
		}
		catch (SQLException ex) {
			throw new DatabaseCloseConnectionException(ex.getMessage());
		}
	}         
}

Java:
public void update(List<Entity> entities) throws DatabaseOpenConnectionException, UpdateDatabaseEntryException, SQLException, DatabaseCloseConnectionException, DatabaseReadDataException {
	Statement statement = null;
	
	try {
		this.createConnection();
		
		//transaktion starten
		connection.setAutoCommit(false);
		connection.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT);
		statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
		
		for (int i = 0; i < entities.size(); i++) {
			
			String  sqlQuery = "UPDATE table .....";
							   
			int resultOfUpdate = statement.executeUpdate(sqlQuery);
			
			if(resultOfUpdate <= 0)
			{
				connection.rollback();
				
				throw new UpdateDatabaseEntryException("Fehler X");
			}
		}
		
		connection.commit();
	} 
	catch (SQLException ex) {
		connection.rollback();
		throw new UpdateDatabaseEntryException(ex.getMessage());
	}        
	finally{
		try{
			if (statement != null) statement.close();

			connection.setAutoCommit(true);
			this.closeConnection();
		}
		catch (SQLException ex) {
			throw new DatabaseCloseConnectionException(ex.getMessage());
		}
	}  
}

Ich hoffe es kann mir einer helfen, weil dass Problem leider innerhalb einer Woche dreimal aufgetreten ist. Es scheint mit der Anzahl der Anfargen zu tun zu haben.

Grüße und Danke
 
Zuletzt bearbeitet:

franzy

Aktives Mitglied
Hallo,

nein, eigentlich nicht. Es sind einfache Updates/Deltes/Inserts auf eine Tabelle. Außer bei den Selects gibt es zwei Abfragen, die über zwei Tabellen gehen. Aber keine großen SQL Abfragen.

Der SQL Express sagt gar nichts in seinen Logs, das wundert mich auch, aber die Tabelle ist definitiv gespeert und es kann nicht zugegriffen werden. Vielleicht schaue ich auch falsch, aber es gibt nur ein Log Verzeichnis.

Grüße
 

franzy

Aktives Mitglied
Guten Morgen,

leider war unser Tomcat7 Server am Wochenende sogar total down. Sogar nicht nur die Webapp sondern ich kam nicht mehr ins Konfigmenü des Tomcats.

Folgende Meldung habe ich X-Mal hintereinander in im Log gelesen nach dem Neustart:

"13.01.2014 07:40:15 org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
SCHWERWIEGEND: The web application [/appXYZ] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@5f2009]) and a value of type [com.sun.webui.theme.ThemeResources] (value [com.sun.webui.theme.ThemeResources@cd78c3]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak."

Grüße und Danke
 

KSG9|sebastian

Top Contributor
Schau doch mal mit VisualVM oder ähnlichem drauf. Und auf dem SQLServer solltest ihr mal Statistiken u.s.w. prüfen. Normale Logs helfen da selten weiter. Alles andere hier ist ins blaue raten. Überhaupt sicher das es an dem Statement liegt?
 

franzy

Aktives Mitglied
Gutne Morgen,

ich bin malhingegangen und habe die libs aus dem Projekt genommen und in das lib Verzeichnis uf dem Tomcat gesteckt. Hab gelesen, dass es scheinbar zu Problemen kommen kann mit dem Treiber für MSSQL, wenn diese direkt im Projekt sind.

Mal schauen!

Grüße
 

mjustin

Aktives Mitglied
Kann es am ResultSet Type (ResultSet.TYPE_SCROLL_INSENSITIVE) liegen?

Wenn ich den Code richtig verstehe, ist in readTable dieser Typ nur dazu verwendet worden, um an das Ende des ResultSets zu springen um dann die Anzahl Datensätze zu erhalten (rowCount), was überflüssig scheint. Ich vermute, der JDBC Treiber wird hier erst einmal das ResultSet komplett einlesen und damit auch entsprechend viel Speicher anfordern, was auch einige Zeit beansprucht.

p.s. unabhängig davon: ResultSet.CONCUR_READ_ONLY ist Default und kann daher weggelassen werdem
 

franzy

Aktives Mitglied
Hallo,

was meinst du mit "was überflüssig scheint."? ich mache das, weil ich wissen möchte ob etwas gefunden wurde. Gibt es da eine bessere Möglichkeit?

Grüße
 

franzy

Aktives Mitglied
Guten Morgen,

ich bekomme das Problem nicht in den Griff!
Das ResultSet lasse ich jetzt ohne ihrgend ein Parameter jetzt laufen und ich lese jetzt nicht mehr zuerst die Anzahl der Zeilen sondern laufe durch die Ergebnismenge und überführe das Ergebnis in eine Liste. Wenn diese dann leer ist, dann dann weiß ich ja das nix da war.

Das Grundproblem ist ja erkannt. Es passiert ein Lock auf die Tabelle (nicht die gesamte Datenbank).

Kann man ein Lock programmiertechnich lösen? Sprich, nach einem Timeout, den ich auch noch nicht weiß wie ich den bei einer SQL Abfrage festlege, ein Befehl auf die Datenbank, die das Lock öffnet.

Gibt es so was?

Grüße
 

Holger

Aktives Mitglied
Ich kenne mich persönlich nicht wirklich mit dem MS SQL Server aus. Aber eigentlich sollte dies über eine Datenbankprozedur machbar sein.
Grüße

Sent drin mobile
 

KSG9|sebastian

Top Contributor
Ein Lock zu entfernen? Das hilft nicht weiter und ich bezweifel stark dass es überhaupt machbar ist.
Nochmal: Aktivier erweiterte Statistiken und analysiert das Problem. Wenn du nicht weißt wie es geht dann holt euch einen DB-Experten dazu! Das Lock passiert nicht ohne Grund. Vermutlich fasst ihr viele Rows im Statement an bzw denkt die DB sie müsste das tun. Was sagt der Explain für den Query? Überhaupt mal einen erstellt?
 

franzy

Aktives Mitglied
Hallo,

wir glauben das Problem gefunden zu haben.

Und zwar werden zu einem festen Zeitpunkt eine Upload von Daten aus der Tabelle nach SAP durchgeführt. Dieser Upload wird von dem SQL Server getriggert. Uns ist aufgefallen, dass zwei gleiche Prozesse gleichzeitig gelaufen sind. Die beide auf diese Daten zugegriffen haben. Dies haben zum einen die Tabelle gespeert und die Daten unterschiedlich upgedatet, was zu schiefständen führte. Zusätzlich werden die Zeilen bei Updates, Inserts, Deletes nicht mehr gelockt (connection.setTransactionIsolation(connection.TRANSACTION_READ_UNCOMMITTED);). Somit sperren wir auch nicht. Außerdem haben wir die Sessionzeit von 30min auf 15 min gersetzt.

Die Anwendung läuft jetzt seit einer Woche stabil. Ich hoffe auch weiterhin.

Danke für eure Hilfe und Ideen!

Grüße
 

KSG9|sebastian

Top Contributor
Hast du ne Ahnung was Uncommited Read bedeutet? Damit befördert ihr unter Umständen Datenschrott Richtung SAP weil auch Daten sichtbar sind die noch nicht committet/zurückgerollt wurden. Das ist keine Lösung für euer Problem sondern ein Hack mit dem ein Problem durch ein anderes Problem ersetzt wurde.
 

franzy

Aktives Mitglied
Hallo,

die Daten können ja sichtbar sein, weil sonst kein Anderer zur gleichen Zeit auf den Daten arbeitet. Dein Einwand würde sich doch nur darauf beziehen, wenn mehrere Personen auf den gleichen Daten arbeiten, oder?

Grüße
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
C SQL Statement Web Tier 2

Ähnliche Java Themen

Neue Themen


Oben