tutorials.de Buch-Aktion 02/2012
Like Tree1Danke
  • 1 Beitrag von Franz Degenhardt
ERLEDIGT
JA
ANTWORTEN
7
ZUGRIFFE
1070
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    ElJarno ElJarno ist offline Mitglied Silber
    Registriert seit
    May 2010
    Beiträge
    88
    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ß Jan
    Geändert von ElJarno (20.05.10 um 10:37 Uhr)
     

  2. #2
    Avatar von Franz Degenhardt
    Franz Degenhardt Franz Degenhardt ist offline Mitglied Brokat
    Registriert seit
    Mar 2004
    Ort
    Köln
    Beiträge
    375
    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 heapsize
     
    Denken gefärdet die Gewohnheit

  3. #3
    ElJarno ElJarno ist offline Mitglied Silber
    Registriert seit
    May 2010
    Beiträge
    88
    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
     

  4. #4
    Avatar von Franz Degenhardt
    Franz Degenhardt Franz Degenhardt ist offline Mitglied Brokat
    Registriert seit
    Mar 2004
    Ort
    Köln
    Beiträge
    375
    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

  5. #5
    ElJarno ElJarno ist offline Mitglied Silber
    Registriert seit
    May 2010
    Beiträge
    88
    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:
    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();
        }
    Kann mir vorstellen dass es an den beiden Schleifen liegt. Vielleicht hast du ja einen anderen Ansatz.
    Hier noch der Code zum Einlesen der Pakete aus der DB:
    Code :
    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
    Und Ja es handelt sich um eine OutOfMemory Exception
    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)
     

  6. #6
    deepthroat deepthroat ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jun 2005
    Beiträge
    7.983
     
    If at first you don't succeed, try again. Then quit. No use being a damn fool about it.

  7. #7
    Avatar von Franz Degenhardt
    Franz Degenhardt Franz Degenhardt ist offline Mitglied Brokat
    Registriert seit
    Mar 2004
    Ort
    Köln
    Beiträge
    375
    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.Throwable
    Geändert von Franz Degenhardt (20.05.10 um 16:12 Uhr)
    ElJarno bedankt sich. 
    Denken gefärdet die Gewohnheit

  8. #8
    ElJarno ElJarno ist offline Mitglied Silber
    Registriert seit
    May 2010
    Beiträge
    88
    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

  1. JComboBox mit Daten aus config.xml befüllen
    Von Tinipieps im Forum Java
    Antworten: 11
    Letzter Beitrag: 21.04.10, 15:20
  2. Daten aus einer MYSQL DB ausgeben
    Von axelfxxx im Forum PHP
    Antworten: 1
    Letzter Beitrag: 29.05.09, 19:22
  3. GridView mit Daten aus DB befüllen
    Von keks1984 im Forum .NET Web und Kommunikation
    Antworten: 1
    Letzter Beitrag: 10.09.07, 13:23
  4. Antworten: 0
    Letzter Beitrag: 08.08.07, 10:39
  5. Dropdownlisten variable mit daten befüllen...
    Von Fenriswolf im Forum .NET Archiv
    Antworten: 0
    Letzter Beitrag: 10.12.03, 21:20