Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用hibernate读取大量数据时的OutOfMemory_Java_Hibernate_Orm_Out Of Memory_Batch Processing - Fatal编程技术网

Java 使用hibernate读取大量数据时的OutOfMemory

Java 使用hibernate读取大量数据时的OutOfMemory,java,hibernate,orm,out-of-memory,batch-processing,Java,Hibernate,Orm,Out Of Memory,Batch Processing,我需要从数据库导出大量数据。以下是表示我的数据的类: public class Product{ ... @OneToMany @JoinColumn(name = "product_id") @Cascade({SAVE_UPDATE, DELETE_ORPHAN}) List<ProductHtmlSource> htmlSources = new ArrayList<ProductHtmlSource>(); } getProdu

我需要从数据库导出大量数据。以下是表示我的数据的类:

public class Product{
...

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

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;
    }
问题是,尽管我在读取每个数据块
Product
后清除了会话,但对象在某个地方累积,我遇到了get-OutMemory异常。问题不在于处理代码块,即使没有它,我也会得到内存错误。批处理的大小也不是问题,因为1000个对象很容易放入内存

分析器显示对象在
org.hibernate.engine.StatefulPersistenceContext
类中累积

堆栈跟踪:

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)**

你能发布异常stacktrace吗? 它可以通过为GC传递合适的JVM选项来解决

我认为这是相关的


从StackTrace中可以看出,正在创建一个非常大的字符串并导致异常。

冒着显得愚蠢的风险-您是否考虑过用另一种方式执行此操作


就我个人而言,我会避免在“远离”数据库的地方进行批处理。我不知道您使用的是什么数据库,但通常有一种机制可以有效地将数据集从数据库中拉出来&拉到文件中,即使它在退出时涉及到适度简单的操作。存储过程、特定的导出实用程序。调查您的数据库供应商还提供了哪些功能。

看起来您正在使用起始和结束行号调用getProductIterator(),而getProductIterator()需要起始行和行计数。随着“上限”越来越高,您正在读取更大的数据块。我想您的意思是将batchSize作为第二个参数传递给getProductIterator()。

不是一个直接的答案,但对于这种数据操作,我会使用。

KeithL是正确的-您正在通过一个不断增加的限制。但是,用这种方式把它拆散是没有意义的。滚动光标的全部意义在于一次处理一行,因此无需将其拆分为块。fetch大小以占用更多内存为代价,减少了对数据库的访问。一般模式应为:

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
}
也就是说,错误是getHtmlSources,因此问题可能与会话/光标/滚动问题完全无关。如果这些html字符串很大,并且它们一直都在被引用,那么您可能正在耗尽连续内存


顺便说一句,我没有在ScrollableResults上看到getScrollableResults方法。

stacktrace,但我认为gc的调优不会有帮助。我试过System.gc();在读取新批处理之前,put内存仍然溢出。“session.execute(p);//在上面设置缓存模式的替代方法”此语句为false,缓存模式与二级缓存和查询缓存有关,而不是会话本身。驱逐或明确声明仍然是强制性的。Gab是正确的。我更新了答案以反映这一点。
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
}