Boa tarde pessoal, estou com o seguinte problema preciso ler uma tabela que tem cerca de 700 mil registros e passar esses dados para uma outra tabela. Pra fazer isso eu utilizei os métodos setFirstResult e setMaxResults do hibernate, onde firstResult começa em zero e vai incrementando em 25000 passo o número máximo tbm como 25000, ou seja, busco do registro 0 a 24999, depois de 25000 a 49999 e por ai vai.
isso está dentro de um loop e quando chega na quarta iteração do loop, ou seja, carreguei e inseri 75000 registros ocorre erro de java.lang.OutOfMemoryError
Não consigo entender o pq disso uma vez que os resultados estão “paginados”.
Segue o trecho do loop:
totalInsert = this.total.countInsert();
do {
list.clear();
list= this.packingListDao.findInsert(
firstResult, 25000);
for (PackingListItem packingListItem : list){
count++;
total++;
// alguns new
// algumas buscas em bds
// e os insert dos dados nas novas tabelas
// atribuição de null para objetos que foram criados com o new
}
firstResult += 25000;
System.gc();
} while (count != totalInsert);
e o trecho do dao
@SuppressWarnings("unchecked")
public List<PackingListItem> findInsert(final int firstResult,
final int maxResult) throws Exception {
return this.getHibernateTemplate().executeFind(new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
String query = " from PackingListItem as packing where not "
+ " exists ( select 1 from DpPackListItem as dp where "
+ " dp.cdSExport = packing.cdPackingItem "
+ " and dp.cdSExport = packing.cdPackingList )";
Query sqlQuery = session.createQuery(query);
sqlQuery.setMaxResults(maxResult);
sqlQuery.setFirstResult(firstResult);
return sqlQuery.list();
}
});
}
@rodrigo_gomes, bah não posso fazer bath dos insert porque tem algumas regras de negócio trash ai por baixo…
Teria alguma maneira de desabilitar totalmente o cache da session??
@luistiagos, realmente este procedimento é uma gambiarra, porque imagina se a tabela continuar crescendo… daqui a pouco eu vou ter que aumentar a memória pra quanto?? 1 ou 2 giga? fica inviável essa solução.
@Henrik, existe essa possibilidade fazer esse select com jdbc puro sem prender a função que limita o nº de registros e o firstResult ao um bd especifico?? eu não me lembro mais(isso é o que dá o cara se acostumar com o hibernate )
Eu também acho que JDBC puro traria um melhor resultado.
Mas independente disso.
Diminua o número de objetos por iteração, diminua drasticamente.
Faça a declaração de sua lista dentro do bloco.
totalInsert = this.total.countInsert();
do {
System.gc();
List<PackingListItem> list = this.packingListDao.findInsert(firstResult, 5000);
for (PackingListItem packingListItem : list){
count++;
total++;
}
firstResult += 5000;
} while (count != totalInsert);
De qualquer maneira o hibernate vai criar uma nova lista a cada iteração, e coloque o System.gc na primeira linha do código.
Outra coisa, não necessita atribuir null aos objetos criados, ao final do blogo eles ja ficam disponiveis para a gc.
Se queres delimitar escopo vida, crie blocos para defini-los dentro do bloco while.
Na verdade o hql que apresentaste vai gerar um sql dentro dos padrões ANSI, que roda em quase todos (senão todos) os banco de dados relacionais do mercado.
Daria sim, sem problemas.