# MySQL-Connect mittels Connection Pooling



## KartoffelKiffer (17. Februar 2010)

Hallo,

ich habe eine grundlegende Frage zur Arbeit mit Java und MySQL.

Ich habe eine Klasse Connect, die folgendes Grundgerüst aufzeigt:

```
pc = null;
		MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
		try {
			
			// Connection
			ds.setUrl(ReadConfig.Element("database_connectionstring"));
			ds.setUser(ReadConfig.Element("database_user"));
			ds.setPassword(ReadConfig.Element("database_pass"));
			// Reconnect
			ds.setAutoReconnect(true);
			ds.setAutoReconnectForConnectionPools(true);
			ds.setAutoReconnectForPools(true);
			
			pc = ds.getPooledConnection();
		} catch (SQLException e) {
			
			new Exception(e.toString());
		}
```

Und eine weitere Funktion getConnection, die die Member-Variable pc zurück gibt.

```
try {
		
			return pc.getConnection();
		} catch (Exception e) {
			
			connect();
			
			try {

				return pc.getConnection();
			} catch (Exception ex) {
				
				new Exception(e.toString());
				return null;
			}
		}
```

Sobald ich eine Abfrage an die Datenbank stellen möchte, sieht der Ablauf folgendermaßen aus:

```
Connection con = Connect.getConnection();
			this.stmnt = con.createStatement();
                        ResultSet rs = this.stmnt.executeQuery("SELECT hose FROM kleidung WHERE name='Fritz'");
                        while(rs.next()) {
(...)
}
```

Wenn ich also eine Abfrage absende, erstelle ich jedesmal ein neues ResultSet, das auf (in diesem Falle) this.stmnt zurück greift.

Nun habe ich - wenn ich mehrere Abfragen in der Sekunde absende - einen Engpass, der sich folgendermaßen äußert:


> java.sql.SQLException: Unexpected exception encountered during query.
> com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
> Last packet sent to the server was 12345ms ago.



Manchmal kommt auch folgendes Szenario zustande:


> java.sql.SqlException: Logical handle no longer valid
> com.mysql.jdbc.PacketTooBigException: Packet for query is too large (6644739 > 1047552). You can change this value on the server by setting the max_allowed_packet variable.



Jetzt frage ich mich, wie ich bei vielleicht 30-40 Abfragen (SELECT-Abfragen, alle WHEREs, GROUPs und ORDERs sind vernünftig indiziert) in der Sekunde so einen Engpass bekomme. Es handelt sich dabei um Abfragen über zwei Tabellen. Die eine zählt knapp 3.000 Einträge (wobei zwei Spalten ausgelesen werden) und eine weitere zählt knapp 5.000 Einträge, wo lediglich eine Bedingung auf eine Spalte der Tabelle besteht.

Gehe ich die Abfrage nun generell falsch an oder wo kann dort mein Engpass liegen?

Das grundlegende Problem dabei ist, dass ich nach Erhalt der Exceptions keine weiteren Abfragen mehr an die Datenbank senden kann. Erst., wenn ich den MySQL-Dienst neustarte, ist dies wieder möglich.

Ich hoffe mir kann jemand helfen, auch gerne mit etwas guter Lektüre im Internet. Ich weiß nämlich nicht mehr, was ich noch weiter machen soll/kann.



MFG KK


----------



## fassy (17. Februar 2010)

Erstmal nimm PreparedStatements statt den query immer literal zu schicken. 

Schließt du die resultSets und Connections oder lässt du sie offen?


----------



## KartoffelKiffer (17. Februar 2010)

Hallo fassy,

ich bin ein Stückchen weiter gekommen und bin von MySQLPooledConnections über zu c3p0 gegangen. Dort sieht es bisher wiefolgt aus:

```
private static ComboPooledDataSource ds = null;
	private static Connection con = null;
	private static boolean db_connected = false;
	
	public static void connect()
	{
		if (isConnected())
		{
			System.out.println("is connected");
			return;
		}
		else
		{ 
			System.out.println("is not connected");
		}
		
		try
		{
			ds = new ComboPooledDataSource(); 
			ds.setDriverClass("org.gjt.mm.mysql.Driver");
			ds.setJdbcUrl(ReadConfig.Element("database_connectionstring")); 
			ds.setUser(ReadConfig.Element("database_user"));
			ds.setPassword(ReadConfig.Element("database_pass"));
			con = ds.getConnection();
			db_connected = true;
		} 
		catch (Exception e)
		{
			System.out.println(e.toString());
			db_connected = false;
		}
	}
	
	public static void distroyConnection()
	{
		try
		{
			DataSources.destroy(ds);
			db_connected = false;
		}
		catch (Exception e)
		{
			System.out.println(e.toString());
		}
	}
	
	public static ResultSet executeQuery(String sql)
	{
		try {
			System.out.println("users: " + ds.getNumUserPools());
			System.out.println("cons: " + ds.getNumConnections());
		} catch (SQLException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		try
		{
			return con.createStatement().executeQuery(sql);
		}
		catch (SQLException e)
		{
			try
			{
				connect();
				return con.createStatement().executeQuery(sql);
			} 
			catch (Exception e2)
			{
				System.out.println(e2.toString());
				return null;
			}
		}
	}
	
	public static boolean isConnected()
	{
		try
		{
			ds.getConnection();
			db_connected = true;
		}
		catch (Exception e)
		{
			db_connected = false;
		}
		return db_connected;
	}
```

Die PreparedStatements waren mir bisher nicht bekannt, danke dafür!

Ich führe also nun bei jeder Abfrage an die Datenbank meine Funktion executeQuery auf, die jedesmal ein Statement erstellt und ein ResultSet zurück gibt.

Komisch ist nur, dass "System.out.println("cons: " + ds.getNumConnections());" bei einem Client 3 zurück gibt und bei einem zweiten 6. Wobei 6 Connections auch das Maximum sind. Kommt ein dritter Client hinzu, bleibt es bei 6 aktiven Connections.

Eine Connection wird nie geschlossen bei mir, da die Applikation dauerhaft in einem Tomcat läuft. Die Funktion distroyConnection wird also nie aufgerufen.

Sobald ich ein Statement bloß einmal erstelle
(bsp)

```
ds = new ComboPooledDataSource(); 
			ds.setDriverClass("org.gjt.mm.mysql.Driver");
			ds.setJdbcUrl(ReadConfig.Element("database_connectionstring")); 
			ds.setUser(ReadConfig.Element("database_user"));
			ds.setPassword(ReadConfig.Element("database_pass"));
			
                        stmnt = ds.getConnection().createStatement();

			db_connected = true;
```
kann ich auch bloß eine Abfrage gleichzeitig an die Datenbank senden. Überlappen sich zwei Abfragen (durch zwei gleichzeitig agierende Clients), so bekomme ich die Exception "Operation not allowed after ResultSet closed".

Also generiere ich für jede Abfrage ein neues Statement und bekomme ein neues ResultSet zurück, welches ich auch nicht wieder schließe.

Gibt es zu dem oben-stehenden noch Fragen/Anmerkungen/Anregungen?



MFG KK


----------

