Pagination JDBC

je veux implémenter la pagination en utilisant JDBC. La chose réelle que je veux savoir est "Comment puis-je obtenir d'abord 50 et ensuite 50 enregistrements à partir de la base de données pour la page 1 et 2 respectivement"

ma requête est Select * from data [table de données contient 20 000 lignes]

pour la page #1 j'obtiens 50 notices et pour la page #2 je veux obtenir 50 notices suivantes. Comment puis-je l'implémenter efficacement dans JDBC?

j'ai cherché et trouvé que rs.absolute(row) est la façon de sauter les enregistrements de première page mais il faut un certain temps sur les grands ensembles de résultats et je ne veux pas supporter cette quantité de temps. En outre, Je ne veux pas utiliser rownum et limit + offset dans la requête parce que ceux-ci ne sont pas bons à utiliser dans la requête, Je ne sais pas pourquoi, encore Je ne veux pas l'utiliser dans la requête.

est-ce que quelqu'un peut m'aider à obtenir le nombre limité ResultSet pour la pagination ou y a-t-il un moyen que JDBC nous donne?

31
demandé sur BalusC 2010-05-05 11:58:49

13 réponses

il n'y a pas de moyen efficace de le faire en utilisant simplement JDBC. Vous devez formuler la limite à n Lignes et à partir du i-ème article clauses directement au SQL pour qu'il soit efficace. En fonction de la base de données, cela peut en fait être assez facile (voir le mot-clé LIMIT de MySQL), sur D'autres bases de données comme Oracle il peut être un peu plus délicat (implique sous-Query et en utilisant rownum pseudo colonne).

voir ce JDBC Tutoriel Sur La Pagination: http://java.avdiel.com/Tutorials/JDBCPaging.html

25
répondu psp 2012-07-12 08:05:10

vous devez interroger seulement les données que vous en fait besoin d'afficher sur la page courante. Ne pas transporter l'ensemble des données dans la mémoire de Java et ensuite filtrer là. Cela ne ferait que ralentir inutilement les choses.

si vous avez réellement un moment difficile à mettre en œuvre correctement et / ou la figuration de la requête SQL pour la base de données spécifique, alors jetez un oeil à ma réponse ici .

mise à jour: puisque vous utilisez Oracle, voici un extrait ciblé par Oracle de la réponse susmentionnée:

dans Oracle vous avez besoin d'un sous-article avec rownum clause qui devrait ressembler à:

private static final String SQL_SUBLIST = "SELECT id, username, job, place FROM"
    + " (SELECT id, username, job, place FROM contact ORDER BY id)"
    + " WHERE ROWNUM BETWEEN %d AND %d";

public List<Contact> list(int firstrow, int rowcount) {
    String sql = String.format(SQL_SUBLIST, firstrow, firstrow + rowcount);

    // Implement JDBC.
    return contacts;
}
17
répondu BalusC 2017-05-23 12:25:55

avertissement: ce billet de blog sur la pagination SQL et la pagination JDBC est posté par moi.

sans tenir compte de la pagination en hibernation, nous pouvons utiliser la pagination SQL / pagination JDBC

pagination SQL

il y a deux approches de base:

  1. exploitation sur fragmentaire ensemble de résultats (Nouvelle Requête pour Chaque Page)
  2. exploitation sur jeu de résultats complet

La façon de le faire est spécifique SQL

pour MySQL / beaucoup D'autres SQL il peut être fait avec Limite et offset

Postgresql: http://microjet.ath.cx/WebWiki/ResultPaginationWithPostgresql.html

dans Oracle, il utilise la même forme que pour traiter "top-n query" par exemple qui sont les 5 employés les mieux payés, qui est optimisé

select *   from ( select a.*, rownum rnum

from ( YOUR_QUERY_GOES_HERE -- including the order by ) a

where rownum <= MAX_ROWS )

where rnum >= MIN_ROWS

Voici une explication très détaillée sur la ligne-NUM

Similaire à ce Thread

Pagination JDBC

la question qui vient à l'esprit est: quand j'exécute le SQL, comment le résultat est-il chargé? Immédiatement ou sur demande? même que ce fil ainsi

tout D'abord, nous devons comprendre quelques bases de JDBC, à partir de Oracle

Par javadoc: déclaration.execute ()

execute: Returns true if the first object that the query returns is a ResultSet object. Use this method if the query could return one or more ResultSet objects. Retrieve the ResultSet objects returned from the query by repeatedly calling Statement.getResutSet.

nous accédons aux données dans le jeu de résultats via un curseur. Notez que ce curseur est différent de celui de DB alors qu'il s'agit d'un pointeur placé initialement avant la première ligne de données.

les données sont récupérées sur demande. alors que quand vous ne l'execute() de l'extraction pour la première fois.

Alors, combien de données sont chargées? Il est configurable. On peut utilisez la méthode java API setFetchSize () sur le jeu de résultats pour contrôler combien de lignes sont récupérées à partir de DB à la fois par le pilote, la taille des blocs qu'il récupère à la fois.

par exemple, supposons que le résultat total soit de 1000. Si la taille du fetch est de 100, La 1ère rangée chargera 100 lignes à partir de DB et la 2ème à la 100ème rangée sera chargée à partir de la mémoire locale.pour interroger la 101e ligne, 100 lignes supplémentaires seront chargées en mémoire.

De JavaDoc

Gives the JDBC driver a hint as to the number of rows that should be fetched from the database when more rows are needed for ResultSet objects genrated by this Statement. If the value specified is zero, then the hint is ignored. The default value is zero.

Notez le mot" indice " - il peut être remplacé par une implémentation spécifique au pilote.

C'est également ce que la fonctionnalité" limiter les lignes à 100 " dans le client comme développeur SQL basé sur.

terminer la solution complète, pour faire défiler les résultats, il faut considérer les types de résultats et ScrollableCursor dans API

on peut trouver un exemple d'implémentation de ce post dans oracle

qui est du livre Oracle Toplink Guide du Développeur Exemple 112 JDBC Driver Fetch Size

ReadAllQuery query = new ReadAllQuery();

query.setReferenceClass(Employee.class);

query.setSelectionCriteria(new ExpressionBuilder.get("id").greaterThan(100));

// Set the JDBC fetch size

query.setFetchSize(50);

// Configure the query to return results as a ScrollableCursor

query.useScrollableCursor();

// Execute the query

ScrollableCursor cursor = (ScrollableCursor) session.executeQuery(query);

// Iterate over the results

while (cursor.hasNext()) {

System.out.println(cursor.next().toString());

}

cursor.close();

.....................

après tout, les questions se réduisent à

Quelle est la meilleure façon de faire la pagination?

Note le SQL devrait être de l'ORDRE par faire sens dans le SQL approche,

sinon il est possible d'afficher à nouveau quelques lignes dans la page suivante.

ci-dessous quelques points de la documentation de Postgresql sur le pilote JDBC et d'autres réponses SO

tout d'abord, la requête originale devrait avoir un ordre Par clause afin de faire fonctionner la solution de paging raisonnablement. Sinon, il serait parfaitement valide pour Oracle de retourner les mêmes 500 lignes pour la première page ,la deuxième page, et la nième page

la différence majeure est pour la voie JDBC, il est nécessaire de maintenir la connexion pendant le chargement. Cela peut ne pas être approprié dans l'application web apatride, par exemple.

Pour SQL façon

la syntaxe est spécifique au SQL et peut ne pas être facile à maintenir. Pour JDBC façon

  • la connexion au serveur doit utiliser le protocole V3. C'est la valeur par défaut pour (et n'est supportée que par) les versions 7.4 et tard.
  • le La connexion ne doit pas être en mode autocommit. Backends ferme les curseurs à la fin des transactions, donc en mode autocommit le backend aura fermé le curseur avant que tout puisse être récupéré à partir d'elle.
  • L'énoncé doit être créé avec un type de Jeu de résultats.TYPE_FORWARD_ONLY. C'est la valeur par défaut, donc aucun code ne sera besoin d'être réécrit pour tirer profit de cela, mais il signifie également que vous ne pouvez pas faire défiler en arrière ou autrement sauter dans le Jeu de résultats.
  • la requête donnée doit être une déclaration unique, pas multiple déclarations attachées avec des points-virgule.

une autre lecture

Ce post est sur le réglage des performances optiques de l'extraction du

7
répondu vincentlcy 2017-05-23 12:17:50

si vous utilisez MySQL ou PostgreSQL limit et offset sont vos mots clés. MSSqlServer et Oracle ont des caractéristiques similaires, mais je semble être un peu plus douloureux.

Pour MySQL et PostgreSQL avoir un coup d'oeil ici:

http://www.petefreitag.com/item/451.cfm

Pour Oracle regardez ici:

http://www.oracle-base.com/forums/viewtopic.php?f=2&t=8635

2
répondu Nils Schmidt 2010-05-05 11:09:10

c'est un lien vers une solution d'hibernation pour la pagination des résultats: HQL-Identificateur de ligne pour la pagination

2
répondu Abhishek Gupta 2017-05-23 12:02:34

je sais que cette question Est ancienne, mais c'est comme ça que j'ai mis en œuvre paging, j'espère qu'il aide quelqu'un

int pageNo = ....;    
String query = "SELECT * FROM data LIMIT ";

switch (pageNo) {
case 0: // no pagination, get all rows
    query += Integer.MAX_VALUE; // a big value to get all rows
    break;
case 1: // get 1st page i.e 50 rows
    query += 50;
    break;
default:
    query += String.valueOf((pageNo-1)*50 + 1) ", " + String.valueOf(50);
    break;
}

PreparedStatement ps = connection.prepareStatement(query);
....

faire de la valeur 50 une constante nommée pageSize, pour qu'elle puisse être changée en n'importe quel nombre

2
répondu HeisenBerg 2016-02-12 10:23:42

je comprends implicitement que vous ne voulez pas que la connexion JDBC ait un seul jeu de résultats gigantesque que vous gardez ouvert pour une très longue période et naviguer lorsque nécessaire.

l'approche habituelle est d'ajouter le SQL nécessaire pour obtenir seulement un sous-ensemble de la demande complète, qui est malheureusement différente de base de données à base de données, et rendra vos déclarations SQL spécifique vendeur. Si je me souviens bien, LIMIT est utilisé avec MySQL. Demandez la gamme appropriée pour chaque demande.

je crois aussi que Hibernate contient des fonctionnalités qui vous permettent de le faire pour HQL, mais je ne le connais pas.

1
répondu Thorbjørn Ravn Andersen 2010-05-05 08:11:37

utilisez-vous une sorte de cadre ORM comme hibernate ou même Java Persistence API ou tout simplement SQL?

ma réponse alors: limite d'utilisation et compensation http://www.petefreitag.com/item/451.cfm

ou passer par ROWNUM Operator Vous avez besoin d'une enveloppe autour de votre SQL alors, mais basicaly c'est

  select * from (select bla.*, ROWNUM rn from (
  <your sql here>
  ) bla where rownum < 200) where rn >= 150'
1
répondu Lars 2010-05-05 09:55:55

Oracle supporte la fonction de fenêtre standard ROW_NUMBER () depuis 8i donc vous pouvez utiliser cela. Vous pouvez faire une requête paramétrée de sorte que vous suffit de définir le début et la fin de la ligne. Par exemple:

SELECT * 
   FROM ( SELECT *, ROW_NUMBER() ORDER BY (sort key) AS rowNumber FROM <your table name> ) AS data
WHERE 
   rowNumber>=:start AND
   rowNumber<:end

(si vous n'utilisez pas les paramètres nommés, remplacez :start/:end par le paramètre de position placeholder '?')

voir sélectionner SQL, fonctions de fenêtre sur wikipedia. L'article énumère également les autres DBs qui soutiennent la fonction de fenêtrage standard ROW_NUMBER ().

1
répondu mdma 2010-05-10 22:04:43
PreparedStatement pStmt = // ... however you make it
pStmt.setFetchSize( /* desired number of records to get into memory */ ); 

Note, setFetchSize(int) n'est qu'un indice - la dernière fois que je L'ai utilisé avec MySQL par exemple, il n'était pas supporté. En regardant brièvement la documentation D'Oracle, il semble que leur JDBC la supporte. Je ne me citerai pas là-dessus, mais cela vaut la peine d'essayer au moins; et oui, cette réponse est fragile, mais il pourrait être assez moins de maux de tête que la mise en œuvre de la solution robuste.

essentiellement, vous pouvez émettre la demande tout, et vous obtenez seulement la taille de l'extraction dans la mémoire (vous n'êtes pas tenue sur les résultats précédents). Ainsi, vous définissez votre taille de fetch à 50, faites votre connexion / requête, affichez les 50 premiers résultats (provoquant l'autre fetch pour la prochaine morsure de votre requête) et ainsi de suite.

1
répondu Carl 2010-06-09 13:10:17

entrée:

  1. exemple D'Information D'ordre (A2 ou D3) (a/D ascendant / descendant) + colonne
  2. exemple D'Information D'ordre (A2 ou D3) (a / D ascendant / descendant) + colonne
  3. valeur du filtre
  4. ligne de départ
  5. ligne de départ
  6. nombre maximum de lignes

résultat:

  • valeurs sélectionnées
  • page sélectionnée
  • Indice de la ligne dans cet ordre
  • compterez données disponibles. (Enregistrer une seconde requête)

Avantage de la Requête pour:

  • somme des colonnes disponibles avec ce filtre
  • transférer uniquement la page sélectionnée de db
  • correctement commandé sans SQL dynamique

Désavantage:

  • Oracle Dependend

    sélectionnez X.* à partir de ( sélectionnez C. pk_field, C. numeric_a, C. char_b, C. char_c ROW_NUMBER () over (ORDER BY décoder(?, "A1", to_char(C. numeric_a, "FM00000000"), "A2", C. char_b, "A3", C. char_c,' A') asc , décoder(?, "D1", to_char(C. numeric_a, "FM00000000"), "D2", C. char_b, "D3", C. char_c, 'A') desc, C. pk_field asc

    ) En tant QUE "idx", Compte ( * ) sur (commande par 1) "cnt" de myTable c où c.botte de foin=? ) X où x. " idx " entre le plus grand (nvl(?,1),1) et nvl(?, 1) -1+?

1
répondu SkateScout 2013-07-08 11:00:21

Vous pouvez utiliser la méthode ci-dessous pour cette.

  1. ici rowNo est le numéro de la rangée de départ à partir de laquelle vous voulez pour obtenir n nombre d'enregistrements.
  2. pageSize est le nombre total d'enregistrements que vous voulez récupérer."


     public CachedRowSet getScrollableList(PreparedStatement prestmt, int rowNo)
                {   
                    getPageSize();
                    ResultSet rs = null;
                    CachedRowSet crs = null;
                    try
                    {           
                        rs = prestmt.executeQuery();
                        crs = new CachedRowSetImpl();
                        crs.setPageSize(pageSize);
                        crs.populate(rs, rowNo);
                    }
                    catch (SQLException ex)
                    {
                        logger.error("Exception in DatabaseInterface in getScrollableList() method: "+ ex.getMessage(),ex);
                    }   
                    finally
                    {
                        //close rs
                        //close pstmt
                    }
                    return crs;
                }



 
1
répondu VaibhavSharma 2018-05-25 09:58:24

les codes java suivants fonctionnent bien:

package paginationSample;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

/**
 *
 * @ Nwaeze Emmanuel (FUNAI, 2016)
 */
public class PaginationSample extends javax.swing.JFrame {  
public void getRows() {
Connection con2;
Statement stmt2;
ResultSet rs2;
int j=0;
String sz="";

  try {
// Load MS accces driver class
 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); 
String url = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb, 
  *.accdb)};DBQ=" + "C:\Database2.mdb"; 
try{
con2 = DriverManager.getConnection(url, "user", "");
System.out.println("Connection Succesfull");

 try{
   stmt2=con2.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, 
   ResultSet.CONCUR_UPDATABLE );
   String sql="";

   if (txtpage.getText().trim().equals("") || 
      txtpagesize.getText().trim().equals("")){

    }else{
     int pagesize=Integer.parseInt(txtpagesize.getText());   
     int page=Integer.parseInt(txtpage.getText());
     sql="SELECT * FROM FSRegistration100L WHERE SN >= " +  
    (pagesize*page-pagesize+1) + " AND " + "SN <= " + (pagesize*page);
     rs2=stmt2.executeQuery(sql);
     if (rs2.wasNull()){

     }else{
       while ( rs2.next()){
         sz=sz + rs2.getString("RegNo") + "\n";

          j++;  

        }
       txta.setText(sz);
       txta.append(" Total rows =" + Integer.toString(j));
    } 
    }
      stmt2.close();
      con2.close();
  }
  catch (NullPointerException s){
  System.err.println("Got an exception166! ");
  System.out.println(s.getMessage());
  } 
 } catch (SQLException e1) {
System.err.println("Got an exception1! ");
System.err.println(e1.getMessage());
}
} catch (ClassNotFoundException e2) {
System.err.println("Got an exception2! ");
System.err.println(e2.getMessage());

} 
}



    private void jButton1ActionPerformed(java.awt.event.ActionEvent 
       evt)     {                                         
       // TODO add your handling code here:
        getRows();
    }                                        

    // Variables declaration - do not modify                     
    private javax.swing.JButton jButton1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextArea txta;
    private javax.swing.JTextField txtpage;
    private javax.swing.JTextField txtpagesize;
    // End of variables declaration 
-2
répondu Emmanuel Nwaeze 2016-02-07 00:29:13