Frage

Ich muss eine große Datenmenge aus der Datenbank exportieren. Hier sind Klassen, die meine Daten darstellen:

public class Product{
...

    @OneToMany
    @JoinColumn(name = "product_id")
    @Cascade({SAVE_UPDATE, DELETE_ORPHAN})
    List<ProductHtmlSource> htmlSources = new ArrayList<ProductHtmlSource>();

... }

ProductHtmlSource - Enthält eine große Zeichenfolge, die ich tatsächlich exportieren muss.

Da die Größe exportierter Daten größer ist als der JVM -Speicher, lese ich meine Daten nach Stücken. So was:

final int batchSize = 1000;      
for (int i = 0; i < 50; i++) {
  ScrollableResults iterator = getProductIterator(batchSize * i, batchSize * (i + 1));
  while (iterator.getScrollableResults().next()) {
     Product product = (Product) iterator.getScrollableResults().get(0); 
     List<String> htmls = product.getHtmlSources();
     <some processing>
  }

}

Code von getProductIterator :

public ScrollableResults getProductIterator(int offset, int limit) {
        Session session = getSession(true);
        session.setCacheMode(CacheMode.IGNORE);
        ScrollableResults iterator = session
                .createCriteria(Product.class)
                .add(Restrictions.eq("status", Product.Status.DONE))
                .setFirstResult(offset)
                .setMaxResults(limit)
                .scroll(ScrollMode.FORWARD_ONLY);
        session.flush();
        session.clear();

        return iterator;
    }

Das Problem ist, dass trotz des Löschens von I -Clearing nach dem Lesen jedes Datenanteils Product Objekte sammeln sich irgendwo an und ich stehe aus der Ausnahme vonMemory. Das Problem liegt nicht im Verarbeitungsblock des Codes, auch ohne ihn erhalte ich Speicherfehler. Die Größe der Charge ist auch kein Problem, da 1000 Objekte leicht in den Speicher sitzen.

Profiler zeigte, dass sich Objekte ansammeln org.hibernate.engine.StatefulPersistenceContext Klasse.

Die Stacktrace:

Caused by: java.lang.OutOfMemoryError: Java heap space
    at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:99)
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:518)
    at java.lang.StringBuffer.append(StringBuffer.java:307)
    at org.hibernate.type.TextType.get(TextType.java:41)
    at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:163)
    at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:154)
    at org.hibernate.type.AbstractType.hydrate(AbstractType.java:81)
    at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2101)
    at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1380)
    at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1308)
    at org.hibernate.loader.Loader.getRow(Loader.java:1206)
    at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:580)
    at org.hibernate.loader.Loader.doQuery(Loader.java:701)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
    at org.hibernate.loader.Loader.loadCollection(Loader.java:1994)
    at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.java:36)
    at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:565)
    at org.hibernate.event.def.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:63)
    at org.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:1716)
    at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:344)
    at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
    at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:109)
    at org.hibernate.collection.PersistentBag.size(PersistentBag.java:225)
    **at com.rivalwatch.plum.model.Product.getHtmlSource(Product.java:76)
    at com.rivalwatch.plum.model.Product.getHtmlSourceText(Product.java:80)
    at com.rivalwatch.plum.readers.AbstractDataReader.getData(AbstractDataReader.java:64)**
War es hilfreich?

Lösung

Es sieht so aus, als würden Sie GetProductiterator () mit den Start- und Endzeilennummern anrufen, während GetProductiterator () die Startreihe und eine Zeilenzahl erwartet. Wenn Ihre "Obergrenze" höher wird, lesen Sie Daten in größeren Stücken. Ich denke, Sie wollen Batchsize als zweites Argument für GetProductiterator () bestehen.

Andere Tipps

Keine direkte Antwort, sondern für diese Art von Datenmanipulation würde ich verwenden Die StatinessSession -Schnittstelle.

Keithl hat Recht - Sie geben eine immer größere Grenze. Aber es macht sowieso keinen Sinn. Der springende Punkt eines Scroll -Cursors ist, dass Sie jeweils eine Reihe verarbeiten, sodass sie nicht in Stücke zerlegt werden müssen. Die Abrufgröße reduziert die Reisen zur Datenbank, um mehr Speicher zu verwenden. Das allgemeine Muster sollte sein:

Query q = session.createCriteria(... no offset or limit ...);
q.setCacheMode(CacheMode.IGNORE); // prevent query or second level caching
q.setFetchSize(1000);  // experiment with this to optimize performance vs. memory
ScrollableResults iterator = query.scroll(ScrollMode.FORWARD_ONLY);
while (iterator.next()) {
  Product p = (Product)iterator.get();
  ...
  session.evict(p);  // required to keep objects from accumulating in the session
}

Der Fehler lautet jedoch GethtmlSources, sodass das Problem möglicherweise nicht mit dem Problem mit Sitzung/Cursor/Scroll zusammenhängt. Wenn diese HTML -Saiten riesig sind und sie die ganze Zeit verwiesen werden, geht Ihnen möglicherweise nur das zusammenhängende Speicher aus.

Übrigens, ich sehe keine GetCrollablableresults -Methode bei Scrollableresults.

Auf das Risiko, dumm zu erscheinen - haben Sie darüber nachgedacht, dies anders zu tun?

Persönlich würde ich es vermeiden, eine Stapelverarbeitung aus der Datenbank auszuführen. Ich weiß nicht, welche Datenbank Sie verwenden, aber es gibt normalerweise einen Mechanismus, um einen Datensatz effizient aus der Datenbank und in eine Datei herauszuholen, auch wenn auf dem Weg nach draußen eine mäßig einfache Manipulation beinhaltet. Gespeicherte Verfahren, spezifische Exportversorgungsunternehmen. Untersuchen Sie, was noch in Ihrem Datenbankanbieter verfügbar ist.

Können Sie die Ausnahme -Stacktrace veröffentlichen? Es kann gelöst werden, indem geeignete JVM -Optionen für GC bestanden werden.

Ich denke das ist verwandt - Java Stringbuilder riesiger Overhead.

Schaut aus dem Stacktrace, dass eine sehr große Saite erstellt wird und die Ausnahme verursacht.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top