[Resolvido] Hibernate e OutOfMemoryError

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();
			}
		});
	}

Olá,

Isso vai te ajudar:
http://www.hibernate.org/hib_docs/reference/en/html/batch.html

O outofmemory deve ta acontecendo pq os objetos estão em cache na session.

[]´s

tente aumentar a memoria e a paginação de sua jvm

se estiver usando eclipse vc pode ir nas propriedades do atalho dele e adicionar -Xms 64M -Xmx 600M
isto aumenta a memoria e a paginação

Eu teria feito usando jdbc puro

Voce ja tentou o profile?

opa e ai gurizada.

@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 :frowning: )

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.

Por enquanto é isso…

@nbluis , existe a possibilidade de fazer esse select em jdbc puro sem se “prender” alguma função especifica do banco??

[quote=maiconramones]opa e ai gurizada.

@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??
[/quote]

Não desabilitar, mas você pode remover um objeto do cache e ele vai ser coletado:

http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html#evict(java.lang.Object)

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.

Bom eu vou fazer alguns testes, como são muuiiiitos registros vai demorar um pouquiho mas assim q eu tiver algum retorno eu posto aqui.

Por enquanto obrigado pessoal, e feliz ano novo pra todos ae.

Abraço.