Limpar com segurança a sessão do Hibernate no meio de uma transação grande
Estou usando o Spring + Hibernate para uma operação que requer criação e atualização literalmente de centenas de milhares de itens. Algo assim:
{
...
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
}
}
}
Para me proteger contra a perda de alterações no meio, eu as confirmo imediatamente apósbarDAO.update(bar)
:
HibernateTransactionManager transactionManager = ...; // injected by Spring
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus transactionStatus = transactionManager.getTransaction(def);
transactionManager.commit(transactionStatus);
Neste ponto, devo dizer que todo o processo está sendo executado em uma transação envolvida emorg.springframework.orm.hibernate3.support.ExtendedOpenSessionInViewFilter
(sim, este é um aplicativo da web).
Tudo isso funciona bem com uma exceção: após alguns milhares de atualizações / confirmações, todo o processo fica muito lento, provavelmente devido ao inchaço da memória pela quantidade cada vez maior de objetos mantidos pelo Spring / Hibernate.
No ambiente somente de hibernação, isso seria facilmente solucionável chamandoorg.hibernate.Session#clear()
.
Agora, as perguntas:
Quando é um bom momento paraclear()
? Tem um grande custo de desempenho?Por que não são objetos comobar
oubaz
liberado / GCd automaticamente? Qual é o objetivo de mantê-los na sessão após a confirmação (no próximo ciclo de iteração, eles não são acessíveis de qualquer maneira)? Eu não fiz o despejo de memória para provar isso, mas meu bom pressentimento é que eles ainda estão lá até que saiam completamente. Se a resposta é "cache de hibernação", por que o cache não está liberado na memória disponível?é seguro / recomendado ligarorg.hibernate.Session#clear()
diretamente (tendo em mente todo o contexto da primavera, coisas como carregamento lento etc.)? Existem invólucros / contrapartes Spring utilizáveis para obter o mesmo?Se a resposta à pergunta acima for verdadeira, o que acontecerá com o objetofoo
, assumindoclear()
é chamado dentro do loop? E sefoo.foo()
é um método de carregamento lento?Obrigado pelas respostas.