Ниже функций кода, но В спящем режиме, никогда не отпускает его власти никакого объекта. Вызов 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;
}
}
Я думаю, что одна из моих проблем заключалась в том, что
if (sr.isLast()) {
advanceScroll();
//...
в сочетании с
((Session) Main.em.getDelegate()).clear();
//Also, "Main.em.clear()" should do...
приводила к тому, что база данных очищалась на один прогон слишком рано. Это было причиной исключений, связанных с коллекциями. Коллекции не могут быть обработаны в StatelessSession, так что это исключено. Я не знаю, почему session.evict(currentObject)
не срабатывает, когда Session.clear()
работает, но пока мне придется действовать именно так. Я поставлю очки за ответ тому, кто разберется с этим.
Итак, на данный момент у нас есть ответ. Требуется ручная прокрутка окна, закрытие ScrollableResults не помогает, и мне нужно правильно выполнить Session.clear().
Не используйте здесь stateful session, это просто НЕ подходящий инструмент для просмотра миллионов строк и построения отчета. Вместо этого используйте интерфейс StatelessSession.
Если использования MySQL Connector/J даже этого недостаточно, вам нужно также победить внутреннюю буферизацию, выполняемую драйвером 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();
Я бы предложил пару вещей:
Попробуйте вызвать setCacheMode (CacheMode.IGNORE)
в Criteria, прежде чем открывать его.
В методе advanceScroll (
) добавьте if (sr! = Null) sr.close ();
, чтобы предыдущие результаты 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;
}