# JAVA hängt nach SQL Abfrage



## Die4Me (30. Nov 2006)

Hi,
ich hab folgendes Problem mit Java.
Ich arbeite an einem Projekt, welches sich zu einer DB verbindet, relativ große Datensätze ausliest und diese Daten dann auswertet.
Als Datenbank nutze ich zur Zeit MySQL5 und MySQL4 und als Schnittstelle nutze ich den JDBC von MySQL.
nun habe ich da nun ein großes Problem. Immer, wenn ich ca 50000 Datensätze auslese, dann bleibt Java hängen und ih weiss nicht, woran das liegt.
Bemergkbar macht sich das wie folgt.
Ich übergebe dem Programm meine Anfrage und ich sehe, dass dies die Daten läd, durch eine Prozentanzeige.
Sind diese dann geladen, dann erscheinen auf der GUI die berechneten Daten.
Danach hängt das Programm und ich weiss nicht warum.
Folgende klasse habe ich geschrieben, um eine Verbindung herzustellen:

```
import java.sql.*;
/**
 * Beschreiben Sie hier die Klasse Sql.
 * 
 * @author SKoschmieder
 * @version 21.12.2005
 */
public class Sql
{
    Connection c;
    
    /**
     * Konstruktor fuer Objekte der Klasse Sql.
     * Dieser installiert den jdbc-Treiber
     */
    public Sql()
    {
        try
        {
            Class.forName ("com.mysql.jdbc.Driver").newInstance ();
        }
        catch (Exception ex)
        {
        }
    }

    /**
     * mysql_connect () - Verbindet sich zu einer Datenbank
     * 
     * @param       url         Server
     * @param       user        Nutzer
     * @param       password    Passwort
     * @return      boolean
     */
    public boolean mysql_connect (String url, String user, String password)
    {
        try
        {
            c = DriverManager.getConnection (url, user, password);
            return true;
        }
        catch (SQLException se)
        {
            return false;
        }
    }
    
    /**
     * mysql_select () - Sendet eine Anfrage an die MySQL-Datenbank und gibt das Ergebnis als ResultSet zurueck
     * 
     * @param   sql     sql-Anfrage
     * @return  ResultSet
     */
    public ResultSet mysql_select (String sql)
    {
        try
        {
            Statement s = c.createStatement ();
            return s.executeQuery (sql);
        }
        catch (SQLException e)
        {
            return null;
        }
    }
    
    /**
     * mysql_entry () - Wird benutzt um Datenn in die Datenbak zu schreiben
     * 
     * @param   sql     sql-Befehl
     * @return  boolean
     */
    public boolean mysql_entry (String sql)
    {
        try
        {
            Statement s = c.createStatement ();
            s.execute (sql);
            s.close ();
            return true;
        }
        catch (SQLException se)
        {
            return false;
        }
    }
    
    /**
     * mysql_num_rows () - Zaehlt die zurueckgegebenen Datensaetze in einem ResultSet
     * 
     * @param   rs      ResultSet
     * @return  anz
     */
    public int mysql_num_rows (ResultSet rs)
    {
        try
        {
            int anz = 0;
            while (rs.next ())
            {
                anz++;
            }
            return anz;
        }
        catch (SQLException e)
        {
            return -1;
        }
    }
    
    /**
     * mysql_num_cols () - Gibt die Anzahl der Spalten an
     * 
     * @param   rs  ResultSet
     * @return  anz
     */
    public int mysql_num_cols (ResultSet rs)
    {
        try
        {
            return rs.getMetaData().getColumnCount();
        }
        catch (SQLException e)
        {
            return -1;
        }
    }
    
    /**
     * mysql_fetch_row () - Wandelt das ResultSet in einen String um.
     * 
     * @param   rs      ResultSet
     * @param   pos     Position
     * @return  rs.getString()
     */
    public String[] mysql_fetch_row (ResultSet rs, int pos)
    {
        try
        {
            rs.first ();
            rs.relative(pos);
            String[] res = new String [mysql_num_cols(rs)];
            for (int i = 0; i < res.length; i++)
            {
                res[i] = rs.getString(i+1);
            }
            return res;
        }
        catch (SQLException e)
        {
            return null;
        }
    }
}
```
Wie folgt sieht dann eine normale Anfrage aus:

```
data = null;
    String sql = textArea1.getText();
    ResultSet result = db.mysql_select(sql);
    int anz = db.mysql_num_rows(result);
    data = new String[anz][];
    for (int i = 0; i < anz; i++)
    {
        data[i] = db.mysql_fetch_row(result,i);
        double percent = ((double)i+1)/(double)anz*100;
        textField1.setText(String.valueOf((int)percent)+"% Datensaetze wurden geladen        ("+(i+1)+"/"+anz+")");
    }
    try
    {
        result.close();
    }
    catch(SQLException e){};
    return data;
```
Dort ist nur die Prozentanzeige vorhanden, nich die Daten, die berechnet werden sollen.
ausserdem wollte ich noch sagen, dass ich mich auf eine ArrayNegativeSizeException abgesichert habe, da ich die Exception wieder abfange.
Dies habe ich nun jedoch raus genommen.
Ich wäre dankbar für jede Hilfe.

mfg
die4me

Edit:
sry, hab noch vergessen was zu sagen.
Je mehr Datensätze ich auslese, um so länger hängt das Programm.
Also, es ist schon so, dass es nach einer weile wieder funktioniert.


----------



## Caffè Latte (30. Nov 2006)

Hi,

das kann ein Speicherproblem sein. Monitore mal dein Programm, z.B. mit der JConsole. Es hat auch noch nie geschadet Objekte, die man nicht braucht auf "null" zu setzen, also z.B. bei dir den result. Das erleichtert dem Garbage Collector die Arbeit.

Wenn es daran nicht liegt würde ich mal den DB-Server überwachen. Und wenn es an dem auch nicht liegt das Netzwerk ...


----------



## bronks (1. Dez 2006)

Die4Me hat gesagt.:
			
		

> ... ca 50000 Datensätze auslese, dann bleibt Java hängen und ih weiss nicht, woran das liegt.
> ... dann erscheinen auf der GUI die berechneten Daten ...


So große Datenmengen zu halten ist schon ein Problem. So große Datenmengen sollte man nicht einlesen, weil es auch so keinen Sinn macht und es ein performacetechnisches Desaster ist. Die Berechnungen sollte die Datenbank  durchführen und die fertigen Ergebnisse liefern.


----------



## Die4Me (3. Dez 2006)

Ich werde probieren, alle diese Berechnungen über die Datenbank laufen zu lassen.
Jedoch denke ich, dass 50000 Datensätze noch wenig sind. Denn das Programm sollte mit Datensätzen klar kommen, welche sich so bei 2 Mio bewegen. Dort sind dann 50000 wenig...  :? 
naja.
ich werde mich denn nun mal langsam ran machen und all diese Sachen über die Datenbank berechen.
Jedoch dachte ich, dass Javas Stärken in der berechnung liegen und es dort sehr schnell sein sollte.
thx for help
die4me


----------



## Die4Me (3. Dez 2006)

Jedoch hätte ich noch einen Nachtrag.
wie kommt es, dass ich mit PHP die Datensätze gut auslesen kann?
PHP ist in der Sache ziemlich schnell.
auch der MySQL Query Browser.
Wie wird dort das Problem mit den Datenmengen gelöst?


----------



## bronks (3. Dez 2006)

Die4Me hat gesagt.:
			
		

> Jedoch hätte ich noch einen Nachtrag.
> wie kommt es, dass ich mit PHP die Datensätze gut auslesen kann?
> PHP ist in der Sache ziemlich schnell.
> auch der MySQL Query Browser.
> Wie wird dort das Problem mit den Datenmengen gelöst?


PHP hält die Daten nicht. PHP ist nur ein Script, welches schnell mal durchläuft und danach nichts mehr davon weiß, daß es überhaupt schon mal gelaufen ist. In PHP gibt es keine Arrays. Den Usern wird zwar dauernd erzählt, daß es welche sind, aber in wirklichkeit ist das ein Map. In Java gibt es unterschiedliche Statement- und ResultSetTypen, welche je nach Anwedungsfall spezielle Vorteile bieten.

Der QueryBrowser ließt seitenweise ...

In Deinem o.g. Code sind auch so ein paar ziemlich unbrauchbare Sachen drin. Statt den Arrays solltest Du Maps oder Collections verwenden. Die Art Sätze zu zählen, wie in mysql_num_rows, ist das schlimmste was ich je gesehen habe. Wenn dann mit:


```
rs.last();
int numRows = rs.getRow();
```

Insgesamt sieht der Code leider nicht sehr nach Java aus. Zum einen werden nicht die üblichen techniken verwendet und ich empfehle Dir außerdem die JavaCodeConventions zu lesen bevor Du Dir diese Schreibeweise angewöhnst.


----------



## Die4Me (3. Dez 2006)

Als erstes wollt ich nur mal erwähnen, dass Java und MySQL nur eine Notwendigkeit ist.
und als zweites, ich arbeite noch nicht allzulange mit Java. sind erst 2 Jahre oder so.
Ich tue dies auch nicht auf professioneller Basis. Ist halt "nur" nen Abi-Thema.
Damit meine ich, ich hab mich bis her nicht tiefergreifend mit java beschäftigt.

Und damit meine ich auch, dass ich noch nie was von Maps oder Collections gehört hab.
Ich kenne höchstens noch Listen, weiss aber nicht, ob die für dies programm geeignet wären...


----------



## Die4Me (3. Dez 2006)

Hi, ich habs nun mal mit ner HashMap probiert.
Jedoch ist diese ca 1sekunde langsamer als ein Array, bei ca 57000 Datensätzen.
ich weiss nu nicht, wie das mit der konvertierung zu anderen werten ist, da ich dies bis her noch nicht testen konnte.

zumindest, sieht meine SQL-Klasse nu folgendermaßen aus:

```
import java.sql.*;
import java.util.HashMap;
/**
 * Beschreiben Sie hier die Klasse Sql.
 * 
 * @author SKoschmieder
 * @version 21.12.2005
 */
public class Sql
{
    Connection c;
    
    /**
     * Konstruktor fuer Objekte der Klasse Sql.
     * Dieser installiert den jdbc-Treiber
     */
    public Sql()
    {
        try
        {
            Class.forName ("com.mysql.jdbc.Driver").newInstance ();
        }
        catch (Exception ex)
        {
        }
    }

    /**
     * mysql_connect () - Verbindet sich zu einer Datenbank
     * 
     * @param       url         Server
     * @param       user        Nutzer
     * @param       password    Passwort
     * @return      boolean
     */
    public boolean mysql_connect (String url, String user, String password)
    {
        try
        {
            c = DriverManager.getConnection (url, user, password);
            return true;
        }
        catch (SQLException se)
        {
            return false;
        }
    }
    
    /**
     * mysql_select () - Sendet eine Anfrage an die MySQL-Datenbank und gibt das Ergebnis als ResultSet zurueck
     * 
     * @param   sql     sql-Anfrage
     * @return  ResultSet
     */
    public ResultSet mysql_select (String sql)
    {
        try
        {
            Statement s = c.createStatement ();
            return s.executeQuery (sql);
        }
        catch (SQLException e)
        {
            return null;
        }
    }
    
    /**
     * mysql_entry () - Wird benutzt um Datenn in die Datenbak zu schreiben
     * 
     * @param   sql     sql-Befehl
     * @return  boolean
     */
    public boolean mysql_entry (String sql)
    {
        try
        {
            Statement s = c.createStatement ();
            s.execute (sql);
            s.close ();
            return true;
        }
        catch (SQLException se)
        {
            return false;
        }
    }
    
    /**
     * mysql_num_rows () - Zaehlt die zurueckgegebenen Datensaetze in einem ResultSet
     * 
     * @param   rs      ResultSet
     * @return  anz
     */
    public int mysql_num_rows (ResultSet rs)
    {
        try
        {
            rs.last();
            return rs.getRow();
        }
        catch (SQLException e)
        {
            return -1;
        }
    }
    
    /**
     * mysql_num_cols () - Gibt die Anzahl der Spalten an
     * 
     * @param   rs  ResultSet
     * @return  anz
     */
    public int mysql_num_cols (ResultSet rs)
    {
        try
        {
            return rs.getMetaData().getColumnCount();
        }
        catch (SQLException e)
        {
            return -1;
        }
    }
    
    /**
     * mysql_fetch_row () - Wandelt das ResultSet in einen String um.
     * 
     * @param   rs      ResultSet
     * @param   pos     Position
     * @return  rs.getString()
     */
    public HashMap mysql_fetch_row (ResultSet rs, int pos)
    {
        try
        {
            rs.first ();
            rs.relative(pos);
            int laenge = mysql_num_cols(rs);
            HashMap res = new HashMap(laenge);
            for (int i = 0; i < laenge; i++)
            {
                res.put(i,rs.getObject(i+1));
            }
            return res;
        }
        catch (SQLException e)
        {
            return null;
        }
    }
    
    public long test ()
    {
        mysql_connect("jdbc:mysql://<Server>/<Datenbank>","<User>","<Passwort>");
        long time = System.currentTimeMillis();
        ResultSet rs = mysql_select("SELECT hohe,breitengrad FROM datensatz");
        int anz = mysql_num_rows(rs);
        HashMap data = new HashMap(anz);
        for (int i = 0; i < anz; i++)
        {
            data.put(i,mysql_fetch_row(rs,i));
        }
        try
        {
            rs.close();
        }
        catch(SQLException e) {};
        rs = null;
        return System.currentTimeMillis()-time;
    }
}
```
die Methode test prüft halt die benötigte Zeit.
Ich würde mich über jegliche weitere Hilfe freuen.
CU und bis her danke
die4me


----------

