Pergunta

Preciso exportar grande quantidade de dados do banco de dados. Aqui estão as aulas que representam meus dados:

public class Product{
...

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

... }

ProductHtmlSource - Contém grande string dentro do qual eu realmente preciso exportar.

Como o tamanho dos dados exportados é maior que a memória da JVM, estou lendo meus dados por pedaços. Assim:

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>
  }

}

Código de 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;
    }

O problema é que, apesar da sessão de limpeza após a leitura de cada pedaço de dados Product Objetos se acumulam em algum lugar e eu vou fazer uma exceção de memória. O problema não está no processamento do bloco de código, mesmo sem ele, recebo erros de memória. O tamanho do lote também não é um problema, já que 1000 objetos ficam facilmente na memória.

Profiler mostrou que os objetos se acumulam em org.hibernate.engine.StatefulPersistenceContext classe.

O 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)**
Foi útil?

Solução

Parece que você está chamando getProductiterator () com os números de linha inicial e final, enquanto getProductIerator () espera a linha inicial e uma contagem de linhas. À medida que seu "limite superior" aumenta, você está lendo dados em pedaços maiores. Eu acho que você pretende passar o BatchSize como o segundo argumento para getProductiterator ().

Outras dicas

Não é uma resposta direta, mas para esse tipo de manipulação de dados, eu usaria A interface do apaglessess.

Keithl está certo - você está passando um limite cada vez maior. Mas quebrá -lo dessa maneira não faz sentido de qualquer maneira. O ponto principal de um cursor de rolagem é que você processa uma linha de cada vez, para que não haja necessidade de dividi -lo em pedaços. O tamanho da busca reduz as viagens ao banco de dados ao custo de usar mais memória. O padrão geral deve ser:

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
}

Dito isto, o erro é o GethtmlSources, para que o problema possa não estar completamente relacionado ao problema da sessão/cursor/rolagem. Se essas cordas HTML forem enormes e estão sendo referenciadas o tempo todo, você pode estar ficando sem memória contígua.

BTW, não vejo um método GetSCrollabLeResults no scrollableResults.

Correndo o risco de parecer estúpido - você pensou em fazer isso de outra maneira?

Pessoalmente, eu evitaria fazer processamento em lote que "distante" do banco de dados. Não sei qual banco de dados você está usando, mas geralmente há um mecanismo para retirar com eficiência um conjunto de dados do banco de dados e para um arquivo, mesmo que envolva manipulação moderadamente simples na saída. Procedimentos armazenados, utilitários de exportação específicos. Investigue o que mais está disponível no seu fornecedor de banco de dados.

Você pode postar a exceção Stacktrace? Pode ser resolvido passando opções de JVM adequadas para GC.

Eu acho que isso está relacionado - Java Stringbuilder enorme no alto.

Looks do Stacktrace que uma corda muito grande está sendo criada e causando a exceção.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top