es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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:

  1. Utilice getResultList de JPA y devuelva una Response con la lista como cuerpo. Un MessageBodyWriter 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.
  2. Use getResultStream de JPA y devuelva una Response con el flujo como cuerpo. Un MessageBodyWriter se encargará de serializar el flujo a JSON. Desafortunadamente, esto no funciona porque parece que el EntityManager se cierra después de que se haya ejecutado el método de JAX-RS y antes de que se invoque el MessageBodyWriter. Esto significa que también se cierra el ResultSet subyacente y el escritor ya no puede leer del flujo.
  3. Utilice un StreamingOutput como cuerpo de Response. 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?

Tags:  , , , ,

Answer

  1. Avatar for 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 y setMaxResults 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:

    import javax.inject.Inject;
    import javax.persistence.EntityManager;
    import javax.persistence.TypedQuery;
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.QueryParam;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;
    import java.util.List;
    
    @Path("/data")
    public class DataResource {
    
        @Inject
        EntityManager entityManager;
    
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public Response getData(@QueryParam("page") int page, @QueryParam("size") int size) {
            TypedQuery<data> query = entityManager.createQuery("SELECT d FROM Data d", Data.class);
            query.setFirstResult(page * size);
            query.setMaxResults(size);
            List<data> dataList = query.getResultList();
            return Response.ok(dataList).build();
        }
    }
    

    En este ejemplo, el método getData acepta dos parametros de consulta page y size que se utilizan para especificar el trozo de datos a obtener. El método setFirstResult se utiliza para especificar el desplazamiento (es decir, page * size) y el método setMaxResults 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.

Comments are closed.