1Danke
ERLEDIGT
JA
JA
ANTWORTEN
7
7
ZUGRIFFE
1070
1070
EMPFEHLEN
-
Hi Leute,
soll in einer MySQL DB Datein speichern und bei bedarf auch wieder auslesen. Mein Code unfktioniert soweit. Jedoch hab ich das Problem dass sobald eine Dtaie ein größe von zirka 15 MB überschreitet der Heap von Java überläuft.
Hier mal meine Methode zum befüllen der DB:
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
private void schreibePDFinDB(String dateiID, String pfad, int offsetDatei, int packetGroesse) throws IOException, SQLException { int partOffset = 0; int partBytesRead = 0; int partNr = 0; int partGroesse = 0; File datei = new File(pfad); byte[] bytes = this.liesDatei(datei, offsetDatei); int bytesLeft = bytes.length; while (bytesLeft > 0) { if (bytesLeft < packetGroesse) { partGroesse = bytesLeft; } else { partGroesse = packetGroesse; } partNr += 1; ByteArrayInputStream byteInpStr = new ByteArrayInputStream(bytes, partOffset, partGroesse); dbBinaerDaten.writeBinaerDaten(dateiID, partNr, partBytesRead, byteInpStr); bytesLeft -= partGroesse; partOffset += partGroesse; } }Code :1 2 3 4 5 6 7 8 9 10 11 12 13
public void writeBinaerDaten(String dateiID, int part, int leng, ByteArrayInputStream daten) throws SQLException { String objid = ObjectID.getOBJID(199); java.sql.PreparedStatement ps = this.getConnection().prepareStatement( "INSERT into BINAER_DATEN VALUES(?,?,?,?,?)"); ps.setString(1, objid); ps.setString(2, dateiID); ps.setInt(3, part); ps.setInt(4, leng); ps.setBlob(5, daten); ps.execute(); }
Bei der Methode liesDatei(datei, offsetDatei) entsteht noch kein Fehler. Also muss es an der Befüllung der Datenbank liegen.
Falls dies nicht genügt kann ich den Rest noch hinterher werfen.
Gruß JanGeändert von ElJarno (20.05.10 um 10:37 Uhr)
-
20.05.10 13:02 #2
Hallo,
die JVM - vor allem die aus standardisierten Containern wie Tomcat, appservern - starten eine jvm mit standard Parametern.
Falls du mehr brauchst, parsen von xml ist immer recht teuer (siehe http://de.wikipedia.org/wiki/Streaming_API_for_XML dazu), dann muss man entsprechend die jvm vergrössern.
Beim Starten aus Kommandozeile ist es recht simpel:
Code :1
java -Xms64m -Xmx256m MyClass
Xms -> initial heapsize
XmX -> maximum heapsizeDenken gefärdet die Gewohnheit
-
Oke hab ich mir schon gedacht. Wollte halt nur diese Methode wenn möglich ungehen, desshalb wollte ich die Daten Aufsplitten um genau das zu verhindern dass der Heap Space nicht reicht. Kann es sein dass die Garbage Collection nicht hinetrhekommt. Weil wenn ich die Datei ohne zu splitten der DB übergeb kommt es zu keinem Mangel an Heap Space. Und was genau meinst du mit dem Parsen von XML teuer sei. Wo geschieht dass den in meinem Code. Sorry für die blöde Frage.
Schon mal danke.
Gruß Jan
-
20.05.10 15:27 #4
XML hatte ich gerade im Kopf, war thematisch voll daneben xD.
Die Garbagecollection kann man recht schwer optimieren. Die Logik dahinter ist komplex und hängt von der Nutzung der vm ab. Bei einer grösseren jvm beispielsweise arbeitet die gargabe collection einfach nur "fauler". Sprich sie räumt später auf, da das Speicherlimit später erreicht wird.
Man könnte herausfinden, welche Objekte da den heap so vollmachen. Verschiedene Schleifenkonstrukte über grosse Strukturen können viel Platz verschwenden.
Bei deiner Struktur hat man nach der Einlesemethode schonmal die 15 MB in dem ByteArray stehen. Die bleiben dort bis zum Ende des Programmes.
Bekommst du einen java.lang.OutOfMemoryError? Kannst du den mal posten?
Wenn du dich mit dem heapdump auseinandersetzten möchtest, HAT https://hat.dev.java.net/ ist recht bedienungsfreundlich.
Ansonsten würde ich einfach mal grössere heapsizes testen und schauen ab wann das Programm die 15MB durchbringt.Denken gefärdet die Gewohnheit
-
Wie blöd von mir der Fehler lag nicht beim schreiben in die Datenbank sondern beim wieder heraus holen
.
Hier mal der Code für das Zusammensetzten der Pakte aus der DB:
Kann mir vorstellen dass es an den beiden Schleifen liegt. Vielleicht hast du ja einen anderen Ansatz.Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
private void lesePDFausDB(String dateiID, String pfad) throws SQLException, IOException { String where = "DATEI_ID = '" + dateiID + "'"; String sortBy = "PART"; Vector<Byte> byteDaten = new Vector<Byte>(); Vector<Vector<Object>> vectorDaten = this.dbBinaerDaten.readBinaerDaten(where, sortBy, 0); BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(pfad, true)); for (Vector<Object> daten : vectorDaten) { byte[] bytePart = (byte[]) daten.get(4); for (byte by : bytePart) { byteDaten.add(by); } } byte[] by = new byte[byteDaten.size()]; for (int i = 0; i < byteDaten.size(); i++) { by[i] = byteDaten.get(i); } output.write(by); output.close(); }
Hier noch der Code zum Einlesen der Pakete aus der DB:
Und Ja es handelt sich um eine OutOfMemory ExceptionCode :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
public Vector<Vector<Object>> readBinaerDaten(String where, String sortBy, int sortOrder) throws SQLException { Vector<Vector<Object>> daten = null; StringBuffer sqlB = new StringBuffer(); sqlB.append("select * from BINAER_DATEN "); sqlB.append("where "); sqlB.append(where); sqlB.append(" order by "); sqlB.append(sortBy); if (sortOrder == 1) { sqlB.append(" desc"); } if (!where.contains(";")) sqlB.append(";"); daten = this.readMySQLTable(sqlB.toString()); return daten; }// end of readBlob where
Code :1 2 3 4 5 6 7
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:2760) at java.util.Arrays.copyOf(Arrays.java:2734) at java.util.Vector.ensureCapacityHelper(Vector.java:226) at java.util.Vector.add(Vector.java:728) at com.ed.bp.DB.DBMethods.lesePDFausDB(DBMethods.java:78) at com.ed.bp.DB.DBMethods.main(DBMethods.java:26)
-
20.05.10 16:01 #6
- Registriert seit
- Jun 2005
- Beiträge
- 7.983
Hi.
Schau mal hier: http://www.torsten-horn.de/techdocs/java-sql.htm#BLOB
GrußIf at first you don't succeed, try again. Then quit. No use being a damn fool about it.
-
20.05.10 16:05 #7
toArray() erzeugt eine Kopie der Daten der Collection als ObjectArray.
Als kleine Optimierung könntest du während der letzten Schleife die Vectordaten direkt rausschreiben, anstatt erst alles in einem byteArray zu sammeln.
Oder schon in der Schleife davor, direkt in den OutputStream schreiben, anstatt die bytes des ganzen Vectors zu sammeln.
Führe doch mal das Programm im debug modus aus und schau dir vor der letzten und vorletzten Schleife dir instanziierten Objekte an. Eventuell braucht man davon einige grosse gar nicht.
edit:
kleiner exkurs
OutOfMemoryError extends java.lang.Error implements java.lang.Throwable
IOException extends java.lang.Exception implements java.lang.ThrowableGeändert von Franz Degenhardt (20.05.10 um 16:12 Uhr)
Denken gefärdet die Gewohnheit
-
So habs nun hinbekommen.
Danke noch mal.
Hier noch der Code für spätere Generationen
Zum schreiben einer Datei in die DB:
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
public void writeBinaerDaten(String dateiID, int packetGroesse, File datei) throws SQLException, IOException { BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(datei)); long dateiGroesse = datei.length(); int partNr = 0; if (dateiGroesse <= Integer.MAX_VALUE) { int bytesLeft = (int) dateiGroesse; while (bytesLeft > 0) { String objid = ObjectID.getOBJID(199); java.sql.PreparedStatement ps = this.getConnection().prepareStatement( "INSERT into BINAER_DATEN VALUES(?,?,?,?,?)"); ps.setString(1, objid); ps.setString(2, dateiID); ps.setInt(3, partNr); ps.setInt(4, packetGroesse); ps.setBinaryStream(5, inputStream, packetGroesse); ps.execute(); ps.close(); partNr += 1; bytesLeft -= packetGroesse; } } else { throw new IOException("Datei ist zu groß! " + datei.getName()); } }
Zum herausholen einer Datei aus der DB und die abschließende Speicherung auf der Festplatte.
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
public void readBinaerDaten(String dateiID, int packetGroesse, File datei) throws SQLException, IOException { ResultSet resultSet = null; StringBuffer sqlB = new StringBuffer(); byte[] bytes = null; BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(datei, false)); sqlB.append("select DATEN from BINAER_DATEN "); sqlB.append("where DATEI_ID = '" + dateiID + "'"); sqlB.append(" order by PART"); sqlB.append(";"); resultSet = this.getStatement().executeQuery(sqlB.toString()); while (resultSet.next()) { bytes = resultSet.getBytes("DATEN"); output.write(bytes); } output.close(); resultSet.close(); }
Gruß Jan
Ähnliche Themen
-
JComboBox mit Daten aus config.xml befüllen
Von Tinipieps im Forum JavaAntworten: 11Letzter Beitrag: 21.04.10, 15:20 -
Daten aus einer MYSQL DB ausgeben
Von axelfxxx im Forum PHPAntworten: 1Letzter Beitrag: 29.05.09, 19:22 -
GridView mit Daten aus DB befüllen
Von keks1984 im Forum .NET Web und KommunikationAntworten: 1Letzter Beitrag: 10.09.07, 13:23 -
DropDownList mit Daten aus MS SQL Server 2005 befüllen
Von keks1984 im Forum ASPAntworten: 0Letzter Beitrag: 08.08.07, 10:39 -
Dropdownlisten variable mit daten befüllen...
Von Fenriswolf im Forum .NET ArchivAntworten: 0Letzter Beitrag: 10.12.03, 21:20





Zitieren
Login




