Algoritmo con Pageable

di il
22 risposte

Algoritmo con Pageable

Buongiorno, chiedo il vostro aiuto per la risoluzione di un algoritmo.
Devo fare in modo che vengano aggiunti alla mia lista 30 elementi per volta.
Pagina 0 i primi 30, pagina 1 gli elementi da 31 a 60, e cosi via.

i metodi:
pageable.getPageSize()
pageable.getPageNumber()
pageable.getOffset()  
               List<DTO> dto = new ArrayList<DTO>();
               int sizePagina = pageable.getPageSize();
               int i = 0;
               Boolean  altriRecord = rs.next();
               while ( i < sizePagina && altriRecord) {                                
                  dto.add(elemento da add preso da altre parti ecc ecc) 
Il problema è che in questo modo aggiungo e stampo sempre i primi 30 elementi, non passa al 31esimo, 61esimo ecc ecc
Ho provato svariate strade ma nulla. Così il getOffset che restituisce N elementi da scartare non viene preso in considerazione. Ma come fare per farlo fare da 31 a 60 (e non da 60 a 31) ? Grazie a chi mi aiuterà.

PS so che ci sono modo migliori per gestire la paginazione, ma è richiesto dalla traccia.

22 Risposte

  • Re: Algoritmo con Pageable

    Test90 ha scritto:


    Il problema è che in questo modo aggiungo e stampo sempre i primi 30 elementi, non passa al 31esimo, 61esimo ecc ecc
    Purtroppo di quanto hai esposto si capisce poco/nulla. Dovresti contestualizzare meglio quello che stai facendo. Si vede un rs.next(), quindi stai usando un ResultSet di JDBC? E che query hai fatto? Poi quel pageable di cosa è/da dove arriva? Hai fatto una tua classe Pageable?
    Se non chiarisci il contesto è difficile anche per me dare una risposta più valida ...
  • Re: Algoritmo con Pageable

    andbin ha scritto:



    Purtroppo di quanto hai esposto si capisce poco/nulla. Dovresti contestualizzare meglio quello che stai facendo. Si vede un rs.next(), quindi stai usando un ResultSet di JDBC? E che query hai fatto? Poi quel pageable di cosa è/da dove arriva? Hai fatto una tua classe Pageable?
    Se non chiarisci il contesto è difficile anche per me dare una risposta più valida ...
    la query è una semplice select su di una tabella.
    il pageable viene inizializzato dall'utente e passato quindi dal controller, ci sono le annotation @ApiImplicitParam per size, offset e ordinamento, non ho una sua classe.
  • Re: Algoritmo con Pageable

    Test90 ha scritto:


    la query è una semplice select su di una tabella.
    Facciamo una premessa: se hai es. 40000 record e vuoi fare (giustamente) una query "paginata" usando JDBC, il punto è che con JDBC puro non è proprio semplice farlo, perché non offre di per sé nulla di predefinito/immediato per gestire la paginazione. Generalmente si sfruttano le clausole specifiche di un DBMS (che variano, non c'è uno standard) per pescare solo una parte di tutti i record.

    Tipo ad esempio in MySQL:

    SELECT blabla FROM tabella LIMIT 100,10

    Dove i dati del limit ovviamente sono dinamici in input.
    Questo è quello che si fa tipicamente con JDBC per la paginazione.

    Test90 ha scritto:


    ci sono le annotation @ApiImplicitParam per size, offset e ordinamento, non ho una sua classe.
    Che in questo momento, la @ApiImplicitParam non saprei nemmeno dire di cosa è! Presumo sia di Swagger, OpenAPI o qualcosa del genere. Ma in ogni caso è solo una annotation "dichiarativa" della API, credo NON riguardi affatto il modo con cui viene fatto il binding di un parametro.
  • Re: Algoritmo con Pageable

    andbin ha scritto:


    Facciamo una premessa: se hai es. 40000 record e vuoi fare (giustamente) una query "paginata" usando JDBC, il punto è che con JDBC puro non è proprio semplice farlo, perché non offre di per sé nulla di predefinito/immediato per gestire la paginazione. Generalmente si sfruttano le clausole specifiche di un DBMS (che variano, non c'è uno standard) per pescare solo una parte di tutti i record.

    Tipo ad esempio in MySQL:

    SELECT blabla FROM tabella LIMIT 100,10

    Dove i dati del limit ovviamente sono dinamici in input.
    Questo è quello che si fa tipicamente con JDBC per la paginazione.

    Che in questo momento, la @ApiImplicitParam non saprei nemmeno dire di cosa è! Presumo sia di Swagger, OpenAPI o qualcosa del genere. Ma in ogni caso è solo una annotation "dichiarativa" della API, credo NON riguardi affatto il modo con cui viene fatto il binding di un parametro.
    Yes sono annotation di Swagger.
    Limit ok nella implementazione della query, ma non è disponibile come key da utilizzare. Per questo la soluzione "alternativa" che però non sono riuscito ad implementare partendo dal codice postato in op
  • Re: Algoritmo con Pageable

    Test90 ha scritto:


    Limit ok nella implementazione della query, ma non è disponibile come key da utilizzare.
    Cioè? E allora come è fatta la query?
  • Re: Algoritmo con Pageable

    andbin ha scritto:



    Cioè? E allora come è fatta la query?
    Select campidaselezionare from tabella
    nessun riferimento alla paginazione
  • Re: Algoritmo con Pageable

    Però in generale ti torna che l'algoritmo in op sia sbagliato perché cicla sempre e solo i primi 30 (getpagesize()) senza considerare quelli da scartare (getoffset())
  • Re: Algoritmo con Pageable

    Test90 ha scritto:


    Però in generale ti torna che l'algoritmo in op sia sbagliato perché cicla sempre e solo i primi 30 (getpagesize()) senza considerare quelli da scartare (getoffset())
    A meno che ci sia un rs.next() nel ciclo che non hai mostrato, è sicuramente sbagliato. Il rs.next() va usato tipicamente nella condizione del while.

    while (rs.next()) { .... }

    Se assegni ad una variabile altriRecord, non serve, perché per il ciclo diventa una "costante". E appunto ... non ha senso.

    E se la query ti dà tutti i record (brutto ma inevitabile non avendo la paginazione in query) e tu vuoi prendere solo una porzione dei record (=paginare), sì può ovviamente fare ma non come stai facendo (che è dubbio).

    Basterebbe ciclare sul ResultSet "a vuoto" (senza prendere i dati) fino ad arrivare all'indice di offset e poi da lì in avanti prendere solo N record che sono il pageSize.

    EDIT: e se potessi usare i ResultSet di tipo "scrollable", puoi andare direttamente a quell'offset.
  • Re: Algoritmo con Pageable

    andbin ha scritto:



    A meno che ci sia un rs.next() nel ciclo che non hai mostrato, è sicuramente sbagliato. Il rs.next() va usato tipicamente nella condizione del while.

    while (rs.next()) { .... }

    Se assegni ad una variabile altriRecord, non serve, perché per il ciclo diventa una "costante". E appunto ... non ha senso.

    E se la query ti dà tutti i record (brutto ma inevitabile non avendo la paginazione in query) e tu vuoi prendere solo una porzione dei record (=paginare), sì può ovviamente fare ma non come stai facendo (che è dubbio).

    Basterebbe ciclare sul ResultSet "a vuoto" (senza prendere i dati) fino ad arrivare all'indice di offset e poi da lì in avanti prendere solo N record che sono il pageSize.
    All'interno del ciclo c'è "altriRecord", quindi inteso da me come un rs.next().

    quindi metto rs.next() come condizione del ciclo, ed all'interno la logica che cicla gli elementi da 0 a pageable.getOffSet()+pagsize, che scarta gli elementi fino ad indice pageable.getOffSet() e prende i successivi.

    Ma questo come lo scrivo, con un altro ciclo all'interno del while?
  • Re: Algoritmo con Pageable

    Test90 ha scritto:


    All'interno del ciclo c'è "altriRecord", quindi inteso da me come un rs.next().
    Il next() DEVE essere sempre fatto in ciclo, perché è lui che materialmente sposta da un record al successivo!

    Test90 ha scritto:


    quindi metto rs.next() come condizione del ciclo, ed all'interno la logica che cicla gli elementi da 0 a pageable.getOffSet()+pagsize, che scarta gli elementi fino ad indice pageable.getOffSet() e prende i successivi.

    Ma questo come lo scrivo, con un altro ciclo all'interno del while?
    Se non puoi mettere la paginazione in query (DBMS-specifico) e non puoi/vuoi usare i ResultSet "scrollable", allora se getOffset() è l'offset 0-based si può fare:
            int pageOffset = pageable.getOffset();
            int pageSize = pageable.getPageSize();
    
            // salta i record iniziali non voluti
            for (int i = 0; rs.next() && i < pageOffset; i++)
                ;
    
            // prende i record della pagina
            for (int i = 0; rs.next() && i < pageSize; i++) {
                // estrai il record, mappa nell'oggetto "dto", aggiungi in lista ecc..
            }
    E' inefficiente ....
  • Re: Algoritmo con Pageable

    andbin ha scritto:



    Se non puoi mettere la paginazione in query (DBMS-specifico) e non puoi/vuoi usare i ResultSet "scrollable", allora se getOffset() è l'offset 0-based si può fare:
            int pageOffset = pageable.getOffset();
            int pageSize = pageable.getPageSize();
    
            // salta i record iniziali non voluti
            for (int i = 0; rs.next() && i < pageOffset; i++)
                ;
    
            // prende i record della pagina
            for (int i = 0; rs.next() && i < pageSize; i++) {
                // estrai il record, mappa nell'oggetto "dto", aggiungi in lista ecc..
            }
    E' inefficiente ....
    Ma tutto questi due cicli for all'interno di un while(rs.next()) ? Non ho capito se questa soluzione potrebbe funzionare o è inefficiente.
  • Re: Algoritmo con Pageable

    Test90 ha scritto:


    Ma tutto questi due cicli for all'interno di un while(rs.next()) ? Non ho capito se questa soluzione potrebbe funzionare o è inefficiente.
    No, proprio solo quei 2 cicli che ho scritto e basta. Il primo "salta" dei record per spostarsi sulla pagina, il secondo tratta proprio la "pagina".
    Sì funziona (salvo mie sviste .. l'ho scritto al volo). E sì ... è inefficiente muoversi così per "saltare" es. 10000 record. Dipende cosa c'è sotto ...
  • Re: Algoritmo con Pageable

    Grazie, ho dovuto modificare con i <= pageSize, c'è solo un problema: mi scarta sempre il primo record "disponibile"
    però ora ho una perplessità. Si è deciso di paginare per evitare un OutOfMemory vista la mole di record recuperati. Ma così si aggira il problema?
  • Re: Algoritmo con Pageable

    Test90 ha scritto:


    Grazie, ho dovuto solo modificare con i <= pageSize
    No alt ... perché?
    Il ciclo (il secondo) che ho scritto io è corretto. Se pageSize è 10, cicla 10 volte (ammettendo che ci siano ALMENO ancora altri 10 record disponibili).

    Poi bisogna vedere se il page offset nel tuo caso è inteso 0-based o 1-based. NON lo posso sapere io.

    Test90 ha scritto:


    Si è deciso di paginare per evitare un OutOfMemory vista la mole di record recuperati. Ma così si aggira il problema?
    Dipende a QUALE livello verrebbe fuori un OutOfMemoryError. Se fosse il caso che tiri su tutti i record, es. 100000 e crei un ArrayList con 100000 oggetti allora sì, quello potrebbe causare un OutOfMemoryError, specialmente se ci fossero anche altre richieste concorrenti di quel tipo (sulla stessa o altre tabelle).

    Facendo un ciclo di next() "a vuoto" per scartare es. 90000 record non causa di certo (non credo) un OutOfMemoryError, semmai è inefficiente come tempistiche. Il "peso" maggiore comunque ce l'ha il DB perché deve fare una query su molti più record del necessario. La paginazione già nella query (con le clausole specifiche del DBMS) serve a evitare proprio questo.
Devi accedere o registrarti per scrivere nel forum
22 risposte