以下代码功能,但Hibernate永远不会放任何对象。调用session.clear()
会导致有关获取连接类的异常,并且在检索下一个对象之前调用session.evict(currentObject)
也无法释放内存。最终我耗尽了我的堆空间。
检查我的堆转储,StatefulPersistenceContext是指向我的对象的所有引用的垃圾收集器的根目录。
public class CriteriaReportSource implements JRDataSource {
private ScrollableResults sr;
private Object currentObject;
private Criteria c;
private static final int scrollSize = 10;
private int offset = 1;
public CriteriaReportSource(Criteria c) {
this.c = c;
advanceScroll();
}
private void advanceScroll() {
// ((Session) Main.em.getDelegate()).clear();
this.sr = c.setFirstResult(offset)
.setMaxResults(scrollSize)
.scroll(ScrollMode.FORWARD_ONLY);
offset += scrollSize;
}
public boolean next() {
if (sr.next()) {
currentObject = sr.get(0);
if (sr.isLast()) {
advanceScroll();
}
return true;
}
return false;
}
public Object getFieldValue(JRField jrf) throws JRException {
Object retVal = null;
if(currentObject == null) { return null; }
try {
retVal = PropertyUtils.getProperty(currentObject, jrf.getName());
} catch (Exception ex) {
Logger.getLogger(CriteriaReportSource.class.getName()).log(Level.SEVERE, null, ex);
}
return retVal;
}
}
答案 0 :(得分:4)
不要在这里使用有状态会话,它不是行走数百万行并构建报告的正确工具。请改用The StatelessSession interface。
如果使用MySQL Connector / J即使这还不够,还需要使用this来阻止JDBC驱动程序完成的内部缓冲:
Query query = session.createQuery(query);
query.setReadOnly(true);
// MIN_VALUE gives hint to JDBC driver to stream results
query.setFetchSize(Integer.MIN_VALUE);
ScrollableResults results = query.scroll(ScrollMode.FORWARD_ONLY);
// iterate over results
while (results.next()) {
Object row = results.get();
// process row then release reference
// you may need to evict() as well
}
results.close();
答案 1 :(得分:0)
我会建议一些事情:
在打开之前尝试在条件上调用setCacheMode(CacheMode.IGNORE)
。
在advanceScroll(
)方法中,添加if (sr != null) sr.close();
,以便在重新分配到新的ScrollableResults之前关闭先前的ScrollableResults。
一个问题:调用setMaxSize(),然后跟踪偏移量然后重新打开可滚动结果的原因是什么,为什么不这样做呢?
public CriteriaReportSource(Criteria c) {
this.c = c;
this.sr = c.setCacheMode(CacheMode.IGNORE)
.scroll(ScrollMode.FORWARD_ONLY);
}
public boolean next() {
if (sr.next()) {
currentObject = sr.get(0);
return true;
}
return false;
}
答案 2 :(得分:0)
我认为我的一个问题是
if (sr.isLast()) {
advanceScroll();
//...
结合
((Session) Main.em.getDelegate()).clear();
//Also, "Main.em.clear()" should do...
过早地将数据库冲出一次。这是关于收集的例外的原因。无法在StatelessSession中处理集合,因此不在表中。我不知道为什么session.evict(currentObject)
在Session.clear()
确实有效时无效,但这就是我现在必须处理它的方式。我会把答案点扔给谁能想出那个答案。
所以,现在,我们有答案。需要手动滚动窗口,关闭ScrollableResults没有帮助,我需要正确运行Session.clear()。