Я использую Spring + Hibernate для операции, которая требует создания и обновления буквально сотен тысяч предметов. Что-то вроде этого:
{
...
Foo foo = fooDAO.get(...);
for (int i=0; i<500000; i++) {
Bar bar = barDAO.load(i);
if (bar.needsModification() && foo.foo()) {
bar.setWhatever("new whatever");
barDAO.update(bar);
// commit here
Baz baz = new Baz();
bazDAO.create(baz);
// if (i % 100 == 0), clear
}
}
}
Чтобы защитить себя от потери изменений в середине, я фиксирую изменения сразу после barDAO.update(bar)
:
HibernateTransactionManager transactionManager = ...; // injected by Spring
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus transactionStatus = transactionManager.getTransaction(def);
transactionManager.commit(transactionStatus);
В этот момент я должен сказать, что весь процесс выполняется в транзакции, заключенной в org.springframework.orm.hibernate3.support.ExtendedOpenSessionInViewFilter
(да, это веб-приложение).
Все это прекрасно работает с одним исключением: после нескольких тысяч обновлений/коммитов весь процесс становится очень медленным, скорее всего из-за того, что память раздувается все увеличивающимся количеством объектов, хранящихся в Spring/Hibernate.
В среде только для спящего режима это можно легко разрешить, вызвав org.hibernate.Session#clear()
.
Теперь вопросы:
- Когда это хорошее время для
clear()
? Имеет ли он большие эксплуатационные расходы? - Почему не выделяются объекты типа
bar
илиbaz
/GCd? Какой смысл держать их в сеансе после фиксации (в следующем цикле итерации они еще не достижимы)? Я не сделал дампа памяти, чтобы доказать это, но мое хорошее чувство заключается в том, что они все еще там, пока они не вышли полностью. Если ответ на этот вопрос - "Hibernate cache", то почему кеш не загорелся, когда доступная память опустилась? - безопасно/рекомендуется напрямую звонить
org.hibernate.Session#clear()
(имея в виду весь контекст Spring, такие как ленивая загрузка и т.д.)? Существуют ли какие-либо используемые Spring обертки/копии для достижения того же? - Если ответ на указанный выше вопрос верен, что произойдет с объектом
foo
, предполагая, чтоclear()
вызывается внутри цикла? Что делать, еслиfoo.foo()
является методом ленивой нагрузки?
Спасибо за ответы.