# Problem: Große Datei in MySQL DB importieren.



## meiaestro (30. Jul 2006)

Hallo,

bei der Ausführung nachfolgendem (hier gekürzt) Code erhalte ich folgende Fehlermeldung: *Exception in thread "Thread-2" java.lang.OutOfMemoryError: Java heap space*

Es ist eine Swing Anwendung, in der ich über eine MenüBar folgende Aktion auslöse (geThreaded).


```
public void  actionPerformed(ActionEvent e){
    new Thread() {
        public void run() {
            ---> Starten einer Prozedur um eine Datei einzulesen und Zeilenweise in die DB einzufügen
        }
    }.start();
}
```


In dieser "Prozedur" passiert grob folgendes:


```
//laden des Treibers
Class.forName("org.gjt.mm.mysql.Driver");
//Aufbau der Verbindung
con = DriverManager.getConnection("jdbc:mysql://192.168.1.1/SNOMED_CT", "***","***");

//Eine recht große Datei (26MB) wird Zeichenweise eingelesen und für jede Zeile ein entsprechendes SQL-Statement erzeugt
while ((chr = input.read()) != -1) {

//Datei Parsen und die korrekten Felder und Feldinhalte bestimmen

    try {
        con.createStatement().execute("INSERT INTO " + tableName + " SET " + fieldsValues + ";");
    } 
        catch (SQLException e) 
    {
        e.printStackTrace();
    }

}

//ganz zum Schluss soll die Verbindung zu DB getrennt werden (soweit kommt es nie)
con.close()
```

Nachdem genau 48% der Datei eingelesen wurden erhalte ich die oben genannte Fehlermeldung. Kurz vorher (bei ca. 40% der Datei) ist das Phänomen zu erkennen, dass die Prozessorlast von entspannten 50% auf gestresste 100% ansteigt. Der Speicherverlauf ist undspektakulär.

Entferne ich diese Zeile hier:

```
con.createStatement().execute("INSERT INTO " + tableName + " SET " + fieldsValues + ";");
```
...läuft alles wunderbar durch.

Freue mich über Tipps.


----------



## foobar (30. Jul 2006)

Warum verwendest du keine Batch?

http://java.sun.com/docs/books/tutorial/jdbc/jdbc2dot0/batchupdates.html


----------



## meiaestro (30. Jul 2006)

Danke für den Hinweis. Habs schon ausprobiert. Da bekomme ich den gleichen Fehler.


----------



## foobar (30. Jul 2006)

Hast du irgendwo eine Rekursion? Oder behälst du Objekte im Speicher? Poste doch mal den ganzen Code.


----------



## meiaestro (31. Jul 2006)

sehe grad ich habe Müll geschrieben 

Natürlich musste ich diese Zeile entfernen, damit alles läuft:


```
con.createStatement().execute("INSERT INTO " + tableName + " SET " + fieldsValues + ";");
```

entschuldigt die Verwirrung.


----------



## SamHotte (31. Jul 2006)

Du erzeugst für jedes *Zeichen* ein Statement ... das würde ich mal aus der while-Schleife 'rausnehmen, könnte eine Menge Platz und Zeit sparen.


----------



## Guest (31. Jul 2006)

Bin grad auf der Arbeit und kann daher leider nicht den Source-Code pasten. Natürlich erzeuge ich nicht zu jedem Zeichen ein Statement ;-) Bin ja nicht verrückt :autsch: 

Die Textfiles sehen so aus, dass in der ersten Zeile die Feldnamen stehen (wie bei einer Tabelle). Die Werte sind-TAB-separiert. In den nächsten Zeilen stehen dann die Werte (ebenfalls TAB-separiert). Ich habe einen Parser gebaut, der erst die erste Zeile liest, um die Feldnamen zu bestimmen, und dann Zeilenweise die Werte bestimmt. In der Variable "fieldsValues" stehe dann die Feld-Wert Kombinationen drin:

feld1=wert1, feld2=wert2, feld3=wert3, usw.

Diese werden dann wie beschrieben an die DB geschickt.


----------



## SamHotte (2. Aug 2006)

meiaestro hat gesagt.:
			
		

> ```
> //laden des Treibers
> Class.forName("org.gjt.mm.mysql.Driver");
> //Aufbau der Verbindung
> ...



Also für mich sieht das sehr wohl so aus, als ob du in der while-Schleife für jedes Zeichen ein Statement erzeugst  ???:L


----------



## meiaestro (2. Aug 2006)

Mein Rechner ist grad abgeschmiert, daher kann ich den Source Code noch nicht posten. Aber glaube mir, es gibt ne Abfrage, die da heißt 

```
if ((char)chr == '\r'){
--> führe Query aus
}
```

also immer nach einer Zeile wird die Query ausgeführt. Die Daten kommen ja auch korrekt in der DB an.


----------



## SamHotte (3. Aug 2006)

Ich glaube dir gern, es schien nur eine mögliche Ursache für den Speicherbedarf zu sein (worauf die ursprüngliche Frage abzielte)


----------



## Dragoslav (3. Aug 2006)

Hallo,

müsste das Statement nicht wieder geschlossen werden?

in der Art:
java.sql.Statement stmt = con.createStatement();
stmt.execute("INSERT INTO " + tableName + " SET " + fieldsValues + ";");
stmt.close();

Servus,

   ~Stefan


----------



## Dragoslav (3. Aug 2006)

Hm, hab grad ein bisschen gegoogelt und bin über folgendes gefallen: dev.mysql.com/tech-resources/articles/connection_pooling_with_connectorj.html

Die machen bei setzten das Objekt sogar noch mit Null zurück, also:


```
/* Statment-Objekt außerhalb der Schleife */
java.sql.Statement stmt = null;
/* hier dann in der schleife */
    stmt = con.createStatement();
    stmt.execute("INSERT INTO " + tableName + " SET " + fieldsValues + ";");
    stmt.close(); 
    stmt = null;
```

Ist das vielleicht eine Hilfe für den Garbage-Collector?


----------



## meiaestro (15. Aug 2006)

Problem gelöst:

ein *stmt.close(); * hat geholfen. Der Batch funktionierte auch nicht, da dieser zu groß für den Java Cache wurde :-(

Danke für die Hilfen.


----------

