Paginación con Spring Data

Hace ya un par de años que ando metido en proyectos que usan el framework de Spring. Recientemente, por necesidades del proyecto he necesitado utilizar la paginación. Spring Data nos proporciona mejoras de rendimiento y fiabilidad para nuestra aplicación. Así es como podemos integrarla.

Para que sirve eso de paginar una consulta

Cuando lanzamos una consulta a la base de datos para que nos devuelva un conjunto de objetos, como por ejemplo.


select a from Actor a

Spring data devolverá todas las entradas de dicha tabla, independientemente del como lo mostremos nosotros posteriormente. Es decir, es relativamente sencillo hacer que nuestra aplicación muestre solo 5 elementos de la lista la primera vez, y al darle a siguiente muestre los otros 5. Pues bien, aunque hagamos una paginación visual, realmente estaremos extrayendo todo el conjunto de datos de la bbdd aunque el usuario solo cargue los primeros 5 elementos. Por ello, es fundamental el uso de la paginación que Spring Data nos proporciona.

Spring Data

El uso de esta herramienta, reduce considerablemente el tiempo de consulta, teniendo que extraer solo X valores de la BBDD. Lo que se traduce en una mejora de rendimiento bastante apreciable. Sin embargo, también tiene sus desventajas y es que al tener que hacer varias consultas al servidor, el control de concurrencia puede darnos problemas. Imaginaos que hay varios usuarios tocando los datos ademas de nosotros, en alguna de esas peticiones puede darse la situación de que extraemos un dato incorrecto, o simplemente un dato que no existe.

Como ya he comentado antes, Spring Data nos brinda soporte completo para esta paginación. Crea toda la lógica para implementarlo, como por ejemplo el número de filas y páginas que queremos mostrar. Hacer la implementación es tremendamente sencillo, solamente tendremos que tocar en un par de sitios de nuestra aplicación.

  • En tu repositorio personalizado, extendiendo a PagingAndSortingRepository
  • En el servicio que implementa dicho repositorio. Creando un objeto PageRequest que implementa la interfaz Pageable. Este objeto PageRequest incluye el número de página y el tamaño de la misma. Además, también permite opciones de ordenación que puedes consultar aquí

Implementación

Comenzamos creando un repositorio que extienda a PagingAndSortingRepository


@Repository
public interface TripRepository extends JpaRepository<Trip, Integer>, PagingAndSortingRepository<Trip, Integer> {

    @Query("select c.audits from Trip c where c.id = ?1")
    Collection<Audit> getAuditByTrip(int tripId);

    @Query("select c.notes from Trip c where c.id = ?1")
    Collection<Note> getNotesByTrip(int tripId);

    @Query("select c.relatedTrips from Category c where c = ?1")
    Collection<Trip> tripsGivenACategory(Category category);
}

Simplemente con llevar a cabo esta acción, nuestro repositorio ya tendrá disponible dicha funcionalidad.

Nos vamos ahora a nuestro servicio que implementa dicho repositorio, e implementamos el siguiente método.


@Service
@Transactional
public class TripService {

   // Constructors--------------------------------------------------------------------------------------
   @Autowired
   private TripRepository tripRepository;
   // Managed repository--------------------------------------------------------------------------------
   public TripService() {
      super();
   }

public Iterable<Trip> tripByPage(int pageNumber, int pageSize){
      PageRequest pageRequest = new PageRequest(pageNumber,pageSize);
      Iterable<Trip> res = tripRepository.findAll(pageRequest);
      return  res;
   }
}

Como podemos observar nuestro método tripByPage tiene como argumentos el número de página a extraer y el número de elementos de cada página (para el ejemplo, el tamaño de página lo pondremos como variable, pero lo más normal es que sea un constante ya predefinida) . Lo único que tenemos que hacer es construir el PageRequest con los valores dados. Posteriormente, utilizar el método Crud findAll con el parámetro PageRequest. Esto lanzará una consulta a la base de datos y nos devolverá un resultado paginado. Este resultado podemos guardarlo en un Iterable<T>

Testeo

Ahora solo tenemos que comprobar que los resultados se devuelven correctamente, y que si cambiamos los parámetros obtendremos valores diferentes. Para ello vamos a construir un test JUnit para llevar a cabo dicha prueba.


public void tripsByPage() throws Exception {
//Todos los items de la base de datos
  Collection<Trip> allTrips =  tripService.findAll();
  for(Trip t: allTrips){
    System.out.println(t);
  }

  System.out.println("");

  //Item paginados
  Iterable<Trip> res = tripService.tripByPage(0,2);
  for(Trip t: res){
     System.out.println(t);
  }

}

La ejecución de esta prueba devolverá por un lado todos los ítems de la base de datos, y por otro lado, los mismos items ya paginados. Tras ejecutar obtenemos:


domain.Trip{id=345, version=0}
domain.Trip{id=403, version=0}
domain.Trip{id=341, version=0}
domain.Trip{id=345, version=0}

La paginación devuelve los 2 primeros elementos, ya que hemos especificado que la página solo contiende dos elementos. Veamos que pasa si consultamos la siguiente página cambiando el índice.


Iterable<Trip> res = tripService.tripByPage(1,2);

domain.Trip{id=403, version=0}

Devuelve el Trip que queda por mostrar, luego, nuestra implementación ha funcionado correctamente. Tenemos que tener presente que PageRequest funciona con indexación-cero, es decir, la primera página se encuentra en el índice 0, no en el 1.

Como hemos podido comprobar, la implementación de la paginación es algo tremendamente sencillo y ventajoso ya que nos va a permitir mejorar considerablemente el rendimiento de nuestra aplicación con tan solo unas pocas líneas de código.

One Comment

  • נערות ליווי- israel lady
    at 18 horas ago

    Itís difficult to find well-informed people in this particular topic, but you seem like you know what youíre talking about! Thanks

    Reply

Leave a Comment