WebApp MySQL Connection Loss

Stefan2902

Aktives Mitglied
Hallo,

Ich habe einen Server aufgesetzt und eine Java WebApp deployed. Leider verliert die Applikation nach zur einen Tag die Konnektivität zur Datenbank. Im catalina.out file finde ich diesbezüglich folgende Einträge:

HTML:
SCHWERWIEGEND: Servlet.service() for servlet jsp threw exception
java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.

2012-11-15 06:11:15 - ERROR - de.stefan.tippspiel.Controller : Error in dispatch: javax.servlet.ServletException: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 33.106.864 milliseconds ago.  The last packet sent successfully to the server was 1 milliseconds ago.
org.apache.jasper.JasperException: javax.servlet.ServletException: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 33.106.864 milliseconds ago.  The last packet sent successfully to the server was 1 milliseconds ago.

Nach einer Recherche habe ich festgestellt, dass ich wohl das folgende JDBC Setting machen muss, um die maximale Idle Time zu reduzierent:

I resolved above error by setting following property

jdbc.default.maxIdleTime=3600

Above value is in seconds - It means after every hour it will get new connection(s).

By default maxIdleTime is set as '0'. This means jdbc connection will keep alive in liferay indefinitely.

But corresponding connection instance in MySQL will die after certain time if it is idle. This is defined by wait_timeout variable of MySQL

Mir ist nun überhaupt nicht klar, wo und wie ich das Setting machen kann. Ich habe einen Ubunutu Server 10.04 aufgesetzt. Hier habe ich einen Apache2 mit Tomcat7 und einer Mysql Datenbank.

Muss ich das Setting in irgendeiner Mysql Config Datei vornehmen, oder muss ich irgendein Pooling einrichten?

Gruß

Stefan
 
N

nillehammer

Gast
I resolved above error by setting following property

jdbc.default.maxIdleTime=3600
Das ist ein Property der Connection, das bei Aufruf von DriverManager.getConnection() mitgegeben werden kann:
Java:
Connection conn = null;
Properties connectionProps = new Properties();
connectionProps.put("jdbc.default.maxIdleTime", 3600);
conn = DriverManager.getConnection( "<jdbcUrl>", connectionProps);

Für eine Lösung, wäre es hilfreich, wenn Du schreiben würdest, wie Du die Connections besorgst?
- Machst Du selbst in Deinem Code eine Connection auf und verwendest sie immer wieder?
- Oder holst Du Dir Connections über eine DataSource?

Der aus meiner Sicht sauberste Ansatz für Connections zu einer DB wäre eine DataSource, die vom Container (Tomcat) gemanaged wird und die Du Dir über JNDI holst. Im Tomcat gibt es einen Poolingmechanismus, der mit den von Dir beschriebenen Problemfällen gut umgehen kann. Das meiste ist Konfiguration des Tomcat. Infos findest Du hier:
Apache Tomcat 7 (7.0.32) - JNDI Resources HOW-TO
Apache Tomcat 7 (7.0.32) - JNDI Datasource HOW-TO
 

Stefan2902

Aktives Mitglied
Vielen Dank für diese perfekte Antwort! Ich habe mich an deine Best Practise gehalten und nun folgenden JNDI Eintrag in der context.xml Datei vorgenommen:

[XML]
<Resource
name="jdbc/applikation"
auth="Container"
driverClassName="com.mysql.jdbc.Driver"
maxActive="100"
maxIdle="30"
maxIdleTime="3600"
maxPoolSize="15"
maxWait="10000"
minPoolSize="3"
username="xxxx"
password="xxxx"
type="javax.sql.DataSource"
url="jdbc:mysql://localhost:3306/applikation" />
[/XML]

Im Java Code habe ich nun folgenden Verweis auf diese Resource:

Java:
	public static Connection getConnection() {

		if (connection == null) {

			DataSource ds = null;

			// Obtain our environment naming context
			try {
				Context initCtx = new InitialContext();
				Context envCtx = (Context) initCtx.lookup("java:comp/env");
				// Look up our data source
				ds = (DataSource) envCtx.lookup("jdbc/applikation");

			} catch (NamingException e) {
				e.printStackTrace();
			}

			// Allocate and use a connection from the pool
			try {
				connection = ds.getConnection();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
		return connection;

	}

In meinem Java Code verwende ich dann jeweils getConnection(); am Start vieler Methoden. Ich habe noch zwei kurze Fragen dazu:

a) Ist das Setzen des Parameters "maxIdleTime" ausreichend, um die Verbindungsabbrüche zu vermeiden?

b) Ist die Vorgehensweise, dass ich die Methode getConnection(); am Start vieler Methoden aufrufe best practise oder implementiert man die Datenbankkonnektivität normallerweise anders?

Gruß
Stefan
 
N

nillehammer

Gast
a) Ist das Setzen des Parameters "maxIdleTime" ausreichend, um die Verbindungsabbrüche zu vermeiden?
Ich kann den Parameter "maxIdleTime" weder in der Doku zu den jdbc-Properties des Connector/J (MySQL :: MySQL 5.0 Reference Manual :: 20.3.5.1 Driver/Datasource Class Names, URL Syntax and Configuration Properties for Connector/J) noch in der Doku zu DBCP entdecken (DBCP - Configuration). Ich fürchte also nein. Außerdem sind einige der anderen Parameter widersprüchlich. Z.B. ist "maxPoolSize" kleiner als "maxActive". Diese werde müssten auch garnicht gesetzt werden, solange die Defaultwerte reichen. Lies Dir mal die DBCP-Seite durch. Da kann man den Pool so einstellen, dass er mit einer Query die Connection offen hält. Ich bin mit folgenden Werten auf einer Seite mit wenig Last gut zurecht gekommen:
Code:
initialSize">3
minIdle">3
validationQuery">SELECT 1 FROM eine_TABELLE_deiner_DB
testOnBorrow">false
testWhileIdle">true
poolPreparedStatements">true
maxOpenPreparedStatements">10
b) Ist die Vorgehensweise, dass ich die Methode getConnection(); am Start vieler Methoden aufrufe best practise oder implementiert man die Datenbankkonnektivität normallerweise anders?
Das kann man schon so machen. Schließlich brauchst Du zum Erstellen von Queries ja immer ein Connection-Objekt. Aber so, wie Du es gemacht hast, ist etwas ungewöhnlich:
Java:
public static Connection getConnection() {
 
        if (connection == null) {
Lässt darauf schließen, dass "connection" eine static variable ist. Das ist kontraproduktiv. Mit einem Pool brauchst Du Dir die connection nirgends zu speichern.
Java:
          DataSource ds = null;
 
            // Obtain our environment naming context
            try {
                Context initCtx = new InitialContext();
                Context envCtx = (Context) initCtx.lookup("java:comp/env");
                // Look up our data source
                ds = (DataSource) envCtx.lookup("jdbc/applikation");
 
            } catch (NamingException e) {
                e.printStackTrace();
            }
Der Teil sollte nur einmal laufen und nicht bei jedem Aufruf der Methode. Das ist unnötig.
 

Stefan2902

Aktives Mitglied
Vielen Dank für die schnelle Unterstützung. Heute Morgen habe ich gemerkt, dass irgendetwas an den Parametern nicht stimmen kann, da heute Morgen die Applikation wieder nicht mehr zur Verfügung stand. Habe einfach eine leere, weiße Seite als Response bekommen. Komischerweise gab es im catalina.out File keinerlei Error Messages / Java Exceptions. Der letzte Eintrag war, dass der Server gestern ordnungsgemäß gestartet wurde.

a) Daher wollte ich mal fragen, ob es noch andere Logfiles gibt, dir mir Aufschluss darüber geben können, warum die Seite heute keine Response geliefert hat?

Darüber hinaus habe ich nun die Settings wie folgt angepasst und bin gespannt, ob er Morgen wieder "stehen bleibt":

[XML]
<Resource
name="jdbc/applikation"
auth="Container"
driverClassName="com.mysql.jdbc.Driver"
initialSize="3"
maxOpenPreparedStatements="10"
minIdle="3"
password="xxxx"
poolPreparedStatements="true"
testOnBorrow="false"
testWhileIdle="true"
type="javax.sql.DataSource"
url="jdbc:mysql://localhost:3306/applikation"
username="xxxx"
validationQuery="SELECT 1 FROM user" />
[/XML]

Auch was den Teil der Connection angeht hast du recht, dass ich die Connection als private static deklariert habe. Du sagst ja, dass ich mit einem Pool die Variable nicht Speichern muss. Bin mir aber nicht sicher, wie ich den Code anpassen muss, damit die Methode nur einmal läuft?

b) An welcher Stelle soll ich meine getConnection() denn im Servlet aufrufen und was ist der Rückgabewert? Sorry aber ich stehe da irgendwie auf dem Schlauch?!

Gruß

Stefan
 
N

nillehammer

Gast
a) Daher wollte ich mal fragen, ob es noch andere Logfiles gibt, dir mir Aufschluss darüber geben können, warum die Seite heute keine Response geliefert hat?
Ich kenne Deine Anwendung jetzt nicht, aber normalerweise hat jede Anwendung ggf. eigene Logfiles. Wo die liegen, hängt von der Anwendung ab. Schaue auch mal in dieLogs des Apachen. Vielleicht hat er es nicht geschafft, den Request weiterzuleiten.
Code:
validationQuery="SELECT 1 FROM user"
Setz die Query mal von Hand über das mysql-Tool ab. Nur zur Sicherheit, dass sie auch funktioniert. Du brauchst eine einfache Query, die (mindestens) eine Zeile zurückliefert.
Auch was den Teil der Connection angeht hast du recht, dass ich die Connection als private static deklariert habe. Du sagst ja, dass ich mit einem Pool die Variable nicht Speichern muss. Bin mir aber nicht sicher, wie ich den Code anpassen muss, damit die Methode nur einmal läuft?

b) An welcher Stelle soll ich meine getConnection() denn im Servlet aufrufen und was ist der Rückgabewert? Sorry aber ich stehe da irgendwie auf dem Schlauch?!
Ich würde das Liefern von Connections als transparenten Service sehen. Für einen Service also zunächst die Interface-Definition:
Java:
public interface ConnectionSource {

   public Connection getConnection();
}
Dann die Implementierung. Ich mach DefaultImplementierungen, die keine eigenen Daten halten, gerne als Enum. Gibt's aber auch andere Meinungen zu. Als Klasse geht es natürlich auch. Dann könntest Du die DataSource sogar als Konstruktorparameter übergeben und den ganzen JDNI-Krams auch noch auslagern.
Java:
public enum ConnectionSourceImpl implements ConnectionSource{
  INSTANCE;

  private final DataSource ds;

  private ConnectionSourceImpl() {
    this.ds = initDataSource();
  }

  private final DataSource initDataSource() {
    try {
      Context initCtx = new InitialContext();
      Context envCtx = (Context) initCtx.lookup("java:comp/env");
       // Look up our data source
      this.ds = (DataSource) envCtx.lookup("jdbc/applikation");
    } catch (NamingException e) {
       // e.printStackTrace(); ist nicht so glücklich
       // Dein Programm funktioniert nicht ohne DataSource
       // also werden wir es durch das Weiterwerfen als RuntimeException
       // das Programm beenden
       throw new RuntimeException(e);
    }
  }

  public Connection getConnection() {
    try {
       return this.ds.getConnection();
    } catch (SQLException e) {
       // e.printStackTrace(); ist nicht so glücklich
       // Dein Programm funktioniert nicht ohne connection
       // also werden wir es durch das Weiterwerfen als RuntimeException
       // das Programm beenden
       throw new RuntimeException(e);
    }
  }
}

Und in Deinem Servlet dann:

Java:
// Hier mal direkt auf die public enum-Konstante zugegriffen
// Besser wäre, Wegkapseln und mit Factories oder Dependeny Injection zu arbeiten
private final ConnectionSource cs = ConnectionSourceImpl.INSTANCE;

doGet(...) {

   final Connection connection = this.cs.getConnection();
   ...
}
 
Zuletzt bearbeitet von einem Moderator:

Stefan2902

Aktives Mitglied
Vielen Dank für den Beispiel Code. Habe die Connection nun dementsprechend angepasst. Habe noch zwei kleine Fragen:

a) Wenn ich einen Connection Pool nun verwende, muss ich die Connection dann wieder nach jedem Gebrauch freigeben? Bin mir nicht sicher aber macht es nicht Sinn statement.close(), resultSet.close() und connection.close() auszuführen, um die Connection wieder freizugeben?

b) Leider habe ich mein Problem noch nicht lösen können, dass die Applikation nach ca. einem Tag nicht mehr läuft (weiße Response Seite). Im Catalina.out file finde ich folgende Einträge

Java:
SCHWERWIEGEND: Servlet.service() for servlet jsp threw exception
java.net.SocketException: Broken pipe
	at java.net.SocketOutputStream.socketWrite0(Native Method)
	at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
	at java.net.SocketOutputStream.write(SocketOutputStream.java:153)

...

16.11.2012 05:34:25 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SCHWERWIEGEND: The web application [] appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak.

Hast du eine Idee, wie ich das fixen kann? Vielen Dank für die Unterstützung.

Gruß
Stefan
 
M

maki

Gast
Hast du mal probiert das testOnBorrow auf true zu setzen?

Rufst du auch immer Connection#close() auf?
 

Stefan2902

Aktives Mitglied
Hallo,

Habe jetzt mal testOnBorrow auf "true" gesetzt.

Was das Schließen der Connection angeht, so habe ich das nun wie folgt programmiert:

Java:
public class Klasse {

	private final static ConnectionSource cs = ConnectionSourceImpl.INSTANCE;


public static Methode1{

		final Connection connection = cs.getConnection();

                ..CODE..

		closeConnect(result, statement, connection);

}

public static Methode2{

		final Connection connection = cs.getConnection();

                ..CODE..

		closeConnect(result, statement, connection);

}

	public static void closeConnect(ResultSet resultSet, Statement statement, Connection connection) {

		// Close Resultset
		if (resultSet != null) {
			try {
				resultSet.close();
			} catch (SQLException e) {
				e.printStackTrace();
				log.info("ResultSet closed: " + e.getMessage());
			}
		}
		// Close Statement
		if (statement != null) {
			try {
				statement.close();
			} catch (SQLException e) {
				e.printStackTrace();
				log.info("Statement closed: " + e.getMessage());
			}
		}
		// Close Connection
		if (connection != null) {
			try {
				connection.close();
			} catch (SQLException e) {
				e.printStackTrace();
				log.info("Connection closed: " + e.getMessage());
			}
		}

	}

Macht das so Sinn?

Gruß
Stefan
 
N

nillehammer

Gast
Bei einem Connection Pool gibt es zwei Varianten:
1. testOnBorrow: Der Pool geht davon aus, dass Connections zwischenzeitlich "zu gehen" und prüft deswegen jedes Mal, bevor er eine Connection herausgibt. Funktioniert, hat aber bei Hochlast-Anwendungen den Nachteil, dass oft unnötige Test-Queries ausgeführt werden und, dass, ggf. relativ spät eine neue Connection (physisch) zur DB aufgemacht wird.
2. testWhileIdle: Der Pool testet periodisch in einem extra Thread alle Connections und hält sie damit offen. Das ist performancemäßig besser.

2. War die Variante, in die ich gehen wollte. Da braucht man kein testOnBorrow. Allerdings habe ich wohl einen Parameter vergessen: timeBetweenEvictionRunsMillis muss gesetzt sein (bspw. auf 3600), sonst läuft der Thread nämlich nicht.

a) Wenn ich einen Connection Pool nun verwende, muss ich die Connection dann wieder nach jedem Gebrauch freigeben? Bin mir nicht sicher aber macht es nicht Sinn statement.close(), resultSet.close() und connection.close() auszuführen, um die Connection wieder freizugeben?
Du programmierst so, wie Du es ohne Pool machen würdest. Ein Connection.close() sorgt dafür, dass eine Connection dem Pool zurück gegeben wird.
 

Stefan2902

Aktives Mitglied
Million Thanks for your advise. Solution:

testOnBorrow set to 'true' as well as proper memory management: stmt.close(), resultSet.close() and connection.close() fixed the issue.

Die Anwendung läuft nun stabil seit zwei Tagen!

Nochmals Danke!!
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
I Swing GUI / Webapp..... benötige ein paar Tips / Ratschläge Allgemeine Java-Themen 18
Z WebApp mit Java verbinden. Allgemeine Java-Themen 8
B Dateien / Bilder von "webapp" Ordner bekommen? Allgemeine Java-Themen 1
A Best Practice Seleniumtest als WebApp Allgemeine Java-Themen 6
M Javaprogrammierung in Webapp einbinden Allgemeine Java-Themen 7
F Benachrichtigungs-System Webapp Java Servlet Allgemeine Java-Themen 10
D Tomcat/Derby Webapp Allgemeine Java-Themen 7
N NetBeans WebApp - web.xml Allgemeine Java-Themen 4
D JavaEE-WebApp Pfad auslesen Allgemeine Java-Themen 3
P Class.forName("com.mysql.jdbc.Driver"); ClassNotFoundException: com.mysql.jdbc.Driver Allgemeine Java-Themen 24
N MySQL mit Strings Allgemeine Java-Themen 3
B Schnittstelle zwischen MySQL und Apache Allgemeine Java-Themen 8
C MySQL Tabellen sortieren. Allgemeine Java-Themen 33
O Zugriff auf mySQL ohne JDBC Allgemeine Java-Themen 3
V Maven Maven ClassNotFoundException MySQL JDBC Treiber Allgemeine Java-Themen 1
G Eclipse Java findet MySQL Driver nach export nicht mehr Allgemeine Java-Themen 2
R Praktikums Projekt Java vs MySQL Allgemeine Java-Themen 91
C JPA und mysql Allgemeine Java-Themen 3
D falsche Zeile aus JTable in MySQL gelöscht Allgemeine Java-Themen 6
D Daten in MySQL-Datenbank schreiben Allgemeine Java-Themen 13
J javaFX mySQL Allgemeine Java-Themen 3
B MySQL Eintrag erstellen Allgemeine Java-Themen 3
P MYSQL Datenbank Dump einspielen Allgemeine Java-Themen 1
F eclipse, texlipse, R und mysql Allgemeine Java-Themen 2
H Tablemodel und mysql Allgemeine Java-Themen 8
T Datumsformat für MySQL Allgemeine Java-Themen 4
S ANT mysql treiber einbinden Allgemeine Java-Themen 4
F Ärger mit mySQL Allgemeine Java-Themen 3
S Java Methode um Daten aus MySQL auslesen Allgemeine Java-Themen 11
S Excel in mySQL importieren Allgemeine Java-Themen 3
neurox Tutorial: Hibernate mit MySQL (erste Schritte) Allgemeine Java-Themen 34
M JAVA Timestamp aus Mysql Allgemeine Java-Themen 4
T MySQl Datenbank als Array ausgeben Allgemeine Java-Themen 11
hdi Applet, JavaScript, PHP, mySQL -> Was brauch ich? Allgemeine Java-Themen 3
E MySQL-Datenbank <-> HashMap/TreeMap Allgemeine Java-Themen 1
H Daten aus MySQL datenbank auslesen und in ArrayList stecken Allgemeine Java-Themen 8
G mySQL und JTable Allgemeine Java-Themen 7
G MySql+Java+backup Allgemeine Java-Themen 23
I JAVA+ MySQL locales statement? Allgemeine Java-Themen 2
B Importieren in MySQL mit Java-Programm Allgemeine Java-Themen 15
G mysql datum umwandeln mittels jsp Allgemeine Java-Themen 10
G Mysql --> Datumsformat Allgemeine Java-Themen 7
C Umlaute mysql Allgemeine Java-Themen 3
V MySql db unter Java zum laufen bringen. Allgemeine Java-Themen 2
C Rechte unter WinXP, MySQL-Server per Runtime herunterfahren? Allgemeine Java-Themen 6
G Datum in MySQL Timestamp umwandeln? Allgemeine Java-Themen 10
G Daten aus MySQL-Datenbank an JFreeChart übergeben Allgemeine Java-Themen 3
G MySQL-Problem (LOAD DATA INFILE) Allgemeine Java-Themen 5
F Threadsicherheit von MySQL-Verbindungen Allgemeine Java-Themen 8
su42 Logout, Cut connection Allgemeine Java-Themen 1
javaBoon86 Email Server Connection Problem Allgemeine Java-Themen 1
berserkerdq2 SceneBuilder GUI erstellt, nun muss ich noch ein Polygon erstellen, ist die Connection möglich? Allgemeine Java-Themen 3
S MSSQL Exception & Connection String Allgemeine Java-Themen 19
OnDemand FTP Connection Allgemeine Java-Themen 2
C Connection timed out mit "MediaWikiBot" Allgemeine Java-Themen 0
J XmlBeanFactory connection refused Allgemeine Java-Themen 5
T HTTP Proxy bei URL Connection Allgemeine Java-Themen 6
E NoClassDefFoundError: javax/microedition/io/Connection Allgemeine Java-Themen 2
S brauche Hilfe für ssh connection in java Allgemeine Java-Themen 6
G SVN Connection problem Allgemeine Java-Themen 10
F java.net.ConnectException: Connection timed out Allgemeine Java-Themen 13
P Ethernet connection Allgemeine Java-Themen 3
G httpUnit: Connection timed out Allgemeine Java-Themen 2
G DB connection in anderen Klassen nutzen! Allgemeine Java-Themen 7
M aus java.sql.Connection datenbankname auslesen Allgemeine Java-Themen 3
M connection übergeben Allgemeine Java-Themen 20
G Connection conn in andere Klasse / Objekt weitergeben? Allgemeine Java-Themen 17
S HTTP Connection über einen Proxy Allgemeine Java-Themen 2

Ähnliche Java Themen


Oben