Cómo transmitir grandes cantidades de datos desde una base de datos a través de REST en Quarkus
Estoy implementando un método GET
en Quarkus que debe enviar grandes cantidades de datos al cliente. Los datos se leen desde la base de datos utilizando JPA / Hibernate, se serializan a JSON y luego se envían al cliente. ¿Cómo se puede hacer esto de manera eficiente sin tener todos los datos en memoria? Intenté las siguientes tres posibilidades, todas sin éxito:
- Utilice
getResultList
de JPA y devuelva unaResponse
con la lista como cuerpo. UnMessageBodyWriter
se encargará de serializar la lista a JSON. Sin embargo, esto traerá todos los datos a la memoria, lo que no es factible para una mayor cantidad de registros. - Use
getResultStream
de JPA y devuelva unaResponse
con el flujo como cuerpo. UnMessageBodyWriter
se encargará de serializar el flujo a JSON. Desafortunadamente, esto no funciona porque parece que elEntityManager
se cierra después de que se haya ejecutado el método de JAX-RS y antes de que se invoque elMessageBodyWriter
. Esto significa que también se cierra elResultSet
subyacente y el escritor ya no puede leer del flujo. - Utilice un
StreamingOutput
como cuerpo deResponse
. El mismo problema que en 2. ocurre.
Entonces, mi pregunta es: ¿cuál es el truco para enviar grandes datos leídos a través de JPA con Quarkus?
davy.ai
Un enfoque para enviar eficientemente grandes cantidades de datos al cliente sin tener toda la información en memoria es usar la paginación. En lugar de obtener todos los datos a la vez, los datos se pueden obtener en pedazos más pequeños y enviados al cliente, con el cliente solicitando el siguiente trozo cuando sea necesario. Esto se puede lograr usando los métodos
setFirstResult
ysetMaxResults
de JPA para especificar el desplazamiento y la limitación para cada parte.Aquí hay un ejemplo de implementación utilizando Quarkus y JPA/Hibernate:
En este ejemplo, el método
getData
acepta dos parametros de consultapage
ysize
que se utilizan para especificar el trozo de datos a obtener. El métodosetFirstResult
se utiliza para especificar el desplazamiento (es decir,page * size
) y el métodosetMaxResults
se utiliza para especificar la limitación (es decir,size
) para cada trozo.Al utilizar este enfoque, solo se obtienen y serializan a JSON los datos del trozo actual, lo que evita cargar toda la información en memoria. Luego, el cliente puede solicitar el siguiente trozo incrementando el parámetro de consulta
page
.Tenga en cuenta que este enfoque asume que los datos están ordenados de tal manera que permite una paginación consistente, como usar una columna de ID que esté ordenada en orden ascendente o descendente. Si los datos no están ordenados de manera consistente, se puede necesitar un enfoque alternativo como la paginación con clave.