Leer miles de registros con Hibernate

Vuelvo a lanzar un post, pues pienso que no esta siendo leido en el post anterior.
Disculpen mi insistencia

He tardado en mostrar el codigo que me pedias, pero es que no habia entrado en el foro.

Y precisamente antes de postearlo, he metido el while dentro del metodo pues en el caso real
lo tengo fuera. Mi sorpresa a sido que al probarlo con 3.000.0000 de registro ha dado de nuevo
el error java.lang.OutOfMemoryError y he comprobado que por error habia realizado las pruebas con
180.000. La verdad es que esta solucion funciona bastante mejor que antes de implementar la
solucion que me propusiesteis.

Adjunto el codigo, que va bastante bien, pero ......., yo espero implentar una solucion que me olvide
de tener que preocuparme de la cantidad de registro que me devuelve una consulta.

Adjunto el codigo y marco la linea donde da el error, espero que me podais aportar alguna idea.

@Override
public ScrollableResults HibernateQueryRegisterLot(Object object) {
_logger.info("HibernateQueryRegisterLot");

ScrollableResults ClaseScroll = null;
sessionFactory = HibernateCreateSessionFactory();
Session session = sessionFactory.getCurrentSession();

try {
HibernateBeginTransaction(session);
Criteria criteria = session.createCriteria(object.getClass());
//criteria.add(Restrictions.between("id", 1, 3000000));

****** error es producido en esta sentencia
ClaseScroll = criteria.setCacheMode(CacheMode.IGNORE).scroll(
ScrollMode.FORWARD_ONLY);
****** error es producido en esta sentencia

File fichero = new File("c:/tmp/hola.txt");
if (fichero.exists())
fichero.deleteOnExit();
BufferedWriter bw = new BufferedWriter(new FileWriter(fichero));

int contador = 0;

while (ClaseScroll.next()) {
object = ((Object) ClaseScroll.get(0));
bw.write(contador);
bw.newLine();

if (contador % 5000 == 0) {
System.out.println("Limpio !");
HibernateFlush(session);
HibernateClear(session);
HibernateSystemGc();
}
System.out.println(contador);
contador++;
}
bw.close();
} catch (Exception e) {
_logger.info("Error : " + e);
// e.printStackTrace();
} finally {
}

return ClaseScroll;
}

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ezamudio

no existe

espero implentar una solucion que me olvide de tener que preocuparme de la cantidad de registro que me devuelve una consulta

Eso no existe, a menos que tengas una cantidad infinita de RAM y una JVM que la pueda utilizar.

Imagen de ajesus

Bien ! No existe !

Que filosofia o tecnica tengo que aplicar.
Realizar un count(*) y despues realizar lecturas de la BD en bloques ?????

Un Saludo

Imagen de ezamudio

GC

O puedes hacer un SELECT directamente a la base de datos, con JDBC (no sé si puedas hacer algo así con hibernate) y controlar por completo el ciclo de lectura del ResultSet, contando registros y cada cierto número de lecturas invocar   (ese número lo dejas parametrizable). Pero pues a fin de cuentas esto puede servirte o no, dependiendo de lo que necesites hacer con los datos leídos.

En general, hacer una lectura de cientos de miles o de millones de registros en una aplicación es señal de que hay algo mal. Si los necesitas leer para calcular algo, mejor dale ese trabajo directamente a la base de datos. Si los necesitas leer porque un usuario los pidió, hay que poner algunas restricciones, porque seguramente ese usuario no necesita tener esos millones de registros. Con qué los va procesar? Excel? no tiene la capacidad... con otra base de datos? No puede mejor trabajar directamente entonces con los datos sin tener que pasar por la aplicación?

Imagen de NovatOmar

creo que tu mismo tienes la

creo que tu mismo tienes la solución debido a la memoria con la que cuentas no puedes realizar-lo en un solo query lo recomendable seria trabajar en bloques si necesitas esa cantidad de registros.

Imagen de ajesus

Pues si ! Leer por paquete de x registros

Despues de vuestros comentarios me queda claro que tengo que tratar la informacion por paquetes de x registros.
En cuanto a lo que comentas Ezamundio si existe algo mas, simplemente se trata que en determinas ocasiones en la aplicacion que voy a tener
que implementar se van a tener que descargar todos los registros de una tabla y formatearlos a un fichero de texto plano que otra aplicacion debe de cargar. En este caso se va a tratar de procesos Batch que normalmente se realizaran por la noche.
Lo mas comun sera que se generen consultas normales y algunas con bastantes miles de registros sin llegar a millones, pero en ocasiones se tendra que realizar este tipo de operaciones que comento.
De todas formas con la solucion que cree con vuestros comentarios, permite recuperar muchisimos mas registros que con un ResulSet normal.

Bueno visto lo visto, empezare a preparar una solucion para recuperar la informacion por lotes de x registros como bien dices Ezamundio y NovatOmar.

Muchas gracias a vosostros dos y a los que anteriormente a colaborado en este asunto.
Espero que el codigo que aporte aunque salio de vosotros, pueda servir a alguien.

Un Saludo
Hasta Proxima.

Imagen de ezamudio

en ese caso

En ese caso sí puedes hacer tu ciclo trabajando directo con el ResultSet, porque para el archivo de texto tendrás un FileReader o algo por el estilo, al cual vas escribiendo los datos de lo que ya leíste, pero no tienes que guardar nada más en memoria, por lo que invocar   cada 10mil registros o algo así te sirve bien.

Sin embargo insisto, existen herramientas ya para este tipo de tareas. Lo que describes se llama ETL: Extract, Transform, Load (aunque la última parte sea "cargar" a un simple archivo de texto plano).

Estar invocando el GC dentro de una aplicación puede causarte serios problemas de desempeño, por lo que incluso si llegas a implementar esto en Java, es mejor que lo tengas como un proceso separado que se corra por batch en una JVM separada de tu contenedor.