IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JDBC Java Discussion :

[JDBC] Stocker les résultats d'une requête


Sujet :

JDBC Java

  1. #1
    Membre régulier
    Inscrit en
    Juillet 2004
    Messages
    306
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 306
    Points : 122
    Points
    122
    Par défaut [JDBC] Stocker les résultats d'une requête
    Bonjour,

    je possède une classe ConnectionJDBC.java qui permet la connection à une base de données, d'exécuter des requêtes, etc.

    Voici la méthode permettant d'exécuter des requêtes:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    public ResultSet executeQuery(String query) throws SQLException {
            ResultSet resultQuery;
            try {
                resultQuery=statement.executeQuery(query);
                while(resultQuery.next()) {
                     System.out.println(resultQuery.getString(2) + " " + resultQuery.getString(3));
     
                }
                return resultQuery;
            }
            catch (SQLException ex) {
                System.err.println("Echec de la requête " + query +
                " sur la base de données " + URL + " : " + ex);
                throw ex;
            }
        }
    Cette méthode retourne resultQuery de type ResultSet.
    J'aimerai que cette méthode retourne les données différemment c'est à dire sous forme de tableau, par exemple.
    Le problème du tableau est qu'il est obligatoire avant de l'utiliser de définir sa taille. Or la taille est inconnue avant l'exécution de la requête. Donc, selon moi le tableau ne convient pas.
    J'avais pensé à la liste, mais il ne semble pas évident de faire des liste à deux dimensions, idems pour les sets.

    Pensez-vous que les maps conviendraient ?
    Et les vectors ?

    Merci d'avance.
    Ciao.

  2. #2
    NGY
    NGY est déconnecté
    Membre habitué
    Inscrit en
    Août 2002
    Messages
    137
    Détails du profil
    Informations forums :
    Inscription : Août 2002
    Messages : 137
    Points : 164
    Points
    164
    Par défaut
    Pour résoudre ce type de cas, c'est simple : il faut stocker chaque ligne retournée par ta requête dans un objet.

    Ensuite ta méthode retourne une Collection de ces objets (à toi de voir en fonction de tes besoins : ArrayList, LinkedList, Map, Set, ...).

  3. #3
    Membre régulier
    Inscrit en
    Juillet 2004
    Messages
    306
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 306
    Points : 122
    Points
    122
    Par défaut
    OK,

    je vais partir sur cette piste.

  4. #4
    Membre régulier
    Inscrit en
    Juillet 2004
    Messages
    306
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 306
    Points : 122
    Points
    122
    Par défaut
    Bonjour,

    en fait, comment dois-je m'y prendre exactement ?

    Merci.
    ++

  5. #5
    NGY
    NGY est déconnecté
    Membre habitué
    Inscrit en
    Août 2002
    Messages
    137
    Détails du profil
    Informations forums :
    Inscription : Août 2002
    Messages : 137
    Points : 164
    Points
    164
    Par défaut
    Supposons que tu veuilles récupérer une liste d'employés. Tu as une table EMPLOYE qui contient les colonnes EMP_ID, EMP_NOM, EMP_PRENOM, EMP_SALAIRE.

    En Java, tu écris une classe Employe du style
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    public class Employe {
      private int id;
      private String nom;
      private String prenom;
      private double salaire;
     
       // ... Déclarer les get/set pour chaque attribut
    }
    Ensuite à un moment dans ton programme tu vas charger une liste d'employés :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    private final String SELECT_EMPLOYES = "select EMP_ID, EMP_NOM, EMP_PRENOM, EMP_SALAIRE from EMPLOYES";
     
       ...
     
    private Employe rsToEmploye(ResultSet rs) throws SQLException {
      Employe emp = new Employe();  // Creation d'un nouvel employé
      emp.setId(rs.getInteger("EMP_ID"); // Remplissage des attributs
      emp.setNom(rs.getString("EMP_NOM"));
      emp.setPrenom(rs.getString("EMP_PRENOM"));
      emp.setSalaire(rs.getDouble("EMP_SALAIRE"));
      return emp;
    }
     
       ...
     
    public List chargeEmployes() {
      ResultSet rs = null;
      List liste = null;
      Employe emp = null;
      ...
      rs = statement.executeQuery(SELECT_EMPLOYES);
      if (rs.next()) {  // S'il y a des donnees
        liste = new ArrayList();  // On construit une liste (vide pour l'instant)
        do {  // Et pour chaque ligne du resultSet
          emp = rsToEmploye(rs);  // Recupère l'employe à partir du resultSet
          liste.add(emp);  // Ajout de l'employé à la liste
        }
        while(rs.next());
      }
       ... (fermer le resultset, le statement, enfin faire propore quoi)
     
      return liste;  // Retourne la liste des employés ou null s'il n'y en a aucun
    }
    Voilà, c'est dans cet esprit. Il faut bien sûr rajouter la gestion des exceptions.

    [Edit]Bouh le vilain : j'avais oublié de dire qu'il fallait fermer le resultSet et tout le reste[/Edit]

  6. #6
    Membre régulier
    Inscrit en
    Juillet 2004
    Messages
    306
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 306
    Points : 122
    Points
    122
    Par défaut
    Bonjour,

    en fait je possède une classe ConnectionJDBC.java (que quelqu'un m'a gentiement développé) d'ailleurs si elle lit ce message, encore merci.
    Bah oui je suis encore débutant et j'ai un peu de mal.

    Cette classe gère l'ouverture et la fermeture de la connection, ouvre et ferme le statement, et exécute des requêtes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    /*
     * ConnectionJDBC.java
     *
     * Created on 2 juillet 2005, 11:03
     */
     
    package connectjdbc;
     
    import java.sql.*;
    import java.lang.*;
    import java.util.*;
     
    /**
     * Classe ConnectionJDBC.<p>
     * Le constructeur charge le pilote, appelle les méthodes de création
     * de la connection et du statement.
     * Toutes ces méhodes de création sont privées.
     *
     * Ensuite, la méthode public setQuery(String Requete) permet
     * d'effectuer des requêtes sur la base de données.
     *
     * 
     */
    public class ConnectionJDBC {
     
        private String URL;
     
        private Connection connection;
     
        private Statement statement;
     
        int index[];
        /**
         * Crée une nouvelle instance de ConnectionJDBC
         * et charge le pilote par défaut sun.jdbc.odbc.JdbcOdbcDriver
         * @param URL chaîne de connection
         * @exception ClassNotFoundException si le pilote ne peut être chargé
         * @exception SQLException si la connection à la base échoue
         */
        public ConnectionJDBC(String URL) throws
        ClassNotFoundException, SQLException {
            this("sun.jdbc.odbc.JdbcOdbcDriver", URL);
        }
     
        /**
         * Crée une nouvelle instance de ConnectionJDBC
         * @param driver pilote à charger
         * @param URL chaîne de connection
         * @exception ClassNotFoundException si le pilote ne peut être chargé
         * @exception SQLException si la connection à la base échoue
         */
        public ConnectionJDBC(String driver, String URL) throws
        ClassNotFoundException, SQLException {
            this(driver, URL, null, null);
        }
     
        /**
         * Crée une nouvelle instance de ConnectionJDBC
         * @param driver pilote à charger
         * @param URL chaîne de connection
         * @param user Utilisateur
         * @param password Mot de Passe
         * @exception ClassNotFoundException si le pilote ne peut être chargé
         * @exception SQLException si la connection à la base échoue
         */
        public ConnectionJDBC(String driver, String URL, String user, String password)
        throws ClassNotFoundException, SQLException {
            this.URL = URL;
            index=new int[10];
            try{
                Class.forName(driver);
            }
            catch (ClassNotFoundException ex){
                System.err.println("Erreur dans le chargement du pilote " +
                driver + " : " + ex);
                throw ex;
            }
     
            connection = createConnection(URL, user, password);
            printInfoDB(connection);
            statement = createStatement(connection);
        }
     
        /**
         * Etabli une connection à la base de données
         * @param URL Chaîne de connection
         * @param user Utilisateur
         * @param password Mot de Passe
         * @return la connection à la base de données
         * @exception SQLException si la connection à la base échoue
         */
        private Connection createConnection(String URL, String user, String password)
        throws SQLException {
            try {
                return DriverManager.getConnection(URL, user, password);
            }
            catch (SQLException ex){
                System.err.println("Erreur de connection à la base de données " +
                URL + " : " + ex);
                throw ex;
            }
        }
     
        /**
         * Affiche sur la sortie standard les infos de la base de données
         * @param connection La connection à la base de données
         */
        private void printInfoDB(Connection connection) {
            try {
                DatabaseMetaData metaData = connection.getMetaData();
                System.out.println(metaData.getDatabaseProductName());
                System.out.println(metaData.getDatabaseProductVersion());
                System.out.println(metaData.getDriverName());
            }
            catch (SQLException ex) {
                System.err.println("Impossible d'obtenir les infos " +
                "de la base de données " + URL + " : " + ex);
            }
        }
     
        /**
         * Crée un statement pour la connection donnée
         * @param connection la connection à la base de données
         * @return le statement créé
         * @exception SQLException si la création du statement échoue
         */
        private Statement createStatement(Connection connection) throws SQLException {
            try {
                return connection.createStatement();
            }
            catch (SQLException ex){
                System.err.println("Impossible de créer le statement " +
                "pour la base de données " + URL + " : " + ex);
                throw ex;
            }
        }
     
        /**
         * Exécute une requête
         * @param query la requête à exécuter
         * @return le résultat de la requête
         * @exception SQLException si l'exécution de la requête échoue
         */
        public ResultSet executeQuery(String query) throws SQLException {
            ResultSet resultQuery;
            Ref resultat;
            int index=0;
            try {
                resultQuery=statement.executeQuery(query);
                while(resultQuery.next()) {
                    index=resultQuery.getRow();
                    System.out.println(" "+resultQuery.getString(1)+" "+resultQuery.getString(2));
                }
                return resultQuery;
            }
            catch (SQLException ex) {
                System.err.println("Echec de la requête " + query +
                " sur la base de données " + URL + " : " + ex);
                throw ex;
            }
        }
     
        /**
         * Fermeture de la connection
         * @exception SQLException si la fermeture de la connection échoue
         */
        public void closeConnection() throws SQLException {
            try {
                connection.close();
            }
            catch (SQLException ex){
                System.err.println("Fermeture de la connection " +
                "à la base de données " + URL + " impossible : " + ex);
                throw ex;
            }
        }
    }
    En fait, j'aimerais que la valeur de retour de la méthode executeQuery ne soit pas un ResultSet pour que les objets appelant cette méthode ne soit pas obligés de définir une méthode du genre de rsToEmploye.
    Je voulais que le type de retour de la méthode executeQuery soit plus général, comme une liste par exemple.

    De ce fait, je pourrais peut-être développé une méthode qui transforme les résultats de la requête en liste, par analogie à ta méthode rsToEmploye. Mais dans ce cas, il faudrait que je connaisse un peu plus en détail ma requête. Or, ma méthode se veut plutôt généraliste.

    Qu'en penses-tu ?

  7. #7
    Membre régulier
    Inscrit en
    Juillet 2004
    Messages
    306
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 306
    Points : 122
    Points
    122
    Par défaut
    Pour être un peu plus précis,

    je peux développer une classe SearchFournisseur qui liste tous ou une partie des fournisseurs selon les critères de sélection qui ont été fait.

    Cette classe crée une instance de la classe ConectionJDBC et fait appelle à la méthode de requête. Ensuite, j'affiche le résultat obtenu dans un JTable par exemple ou tout autrement.

    ++

  8. #8
    NGY
    NGY est déconnecté
    Membre habitué
    Inscrit en
    Août 2002
    Messages
    137
    Détails du profil
    Informations forums :
    Inscription : Août 2002
    Messages : 137
    Points : 164
    Points
    164
    Par défaut
    Citation Envoyé par etiennegaloup
    En fait, j'aimerais que la valeur de retour de la méthode executeQuery ne soit pas un ResultSet pour que les objets appelant cette méthode ne soit pas obligés de définir une méthode du genre de rsToEmploye.
    Je voulais que le type de retour de la méthode executeQuery soit plus général, comme une liste par exemple.
    : Je ne te suis pas, ou alors c'est toi qui ne me suis pas !
    C'est exactement ce que fait l'exemple que je t'ai envoyé.
    Le rsToEmploye() est juste là pour alléger la méthode public List chargeEmploye() qui retourne bien une Liste.
    Si tu veux l'appeler executeQuery(), rien ne te l'interdit !

    Citation Envoyé par etiennegaloup
    ... Or, ma méthode se veut plutôt généraliste.
    Si je comprends bien tu voudrais que la méthode executeQuery prenne en paramètre une requête, pour ensuite l'exécuter et retourner une liste.
    Dans ce cas, il suffit de changer 2 lignes dans mon exemple :
    public List chargeEmploye(String requete) et
    rs = statement.executeQuery(requete);
    De ce fait, je pourrais peut-être développé une méthode qui transforme les résultats de la requête en liste, par analogie à ta méthode rsToEmploye. Mais dans ce cas, il faudrait que je connaisse un peu plus en détail ma requête (...)
    Qu'en penses-tu ?
    Je pense que c'est une mauvaise idée.
    Cette façon de faire va rendre ton code plus difficile à maintenir et risque de compliquer des évolutions futures.
    En règle générale, il est préférable de bien découper les rôles attribués à chaque classe.
    Seule la classe SearchFournisseur doit "connaître" le modèle de données (la table et ses colonnes). Elle servira à "convertir" les données issues des requêtes en objet Fournisseur.
    La classe ConnectionJDBC est chargée de gérer les connections avec la base de donnée, mais ne devrait pas "connaître" le modèle.
    Cela permet de rendre indépendantes les classes entre elles. Ce qui fait que si tu modifies la table Fournisseur, cela t'obligera à modifier la classe SearchFournisseur et la classe Fournisseur mais cela ne doit pas impacter ConnectionJDBC.

    Pour moi, la classe SearchFournisseur devrait avoir 1 méthode privée rsToFournisseur, et n méthodes publiques de recherche qui retournent toutes une Liste (selectParNom(String nom), selectParActivite(String codeActivite), selectParCPetActivite(String codePostal, String codeActivite), ...)
    Cela peut paraître un peu lourd mais cela représente d'énormes avantages.

    Pour alléger, on reprend la méthode chargeFournisseur(String requete).
    Chaque méthode de recherche (selectParTruc(), selectParMachin(), ...) met en forme une requête qu'elle passe à chargeFournisseur et retourne la Liste des Fournisseur.

    Ca donne une classe SearchFournisseur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    public classe SearchFournisseur {
      private final String FOURNISSEUR_SELECT = "select tous_les_champs from FOURNISSEUR ";
     
      private ConnectionJDBC connectionJDBC = null; // Servira à accedrer à la BD
     
      // On crée l'objet en lui passant une ConnectionJDBC 
      public SearchFournisseur(ConnectionJDBC cnx) {
        this.connectionJDBC = cnx;
      }
     
      private Fournisseur rsToFournisseur(ResultSet rs) {
        // création + remplissage d'un objet fournisseur à partir du ResultSet
        ...
      }
     
      private Fournisseur chargeFournisseur(String requete) {
        List liste = null;
        Fournisseur f = null;
        ResultSet = connectionJDBC.executeQuery(requete);
        if (rs.next()) {  // S'il y a des donnees
          liste = new ArrayList();  // On construit une liste (vide pour l'instant)
          do {  // Et pour chaque ligne du resultSet
            f = rsToFournisseur(rs);  // Recupère l'employe à partir du resultSet
            liste.add(f);  // Ajout de l'employé à la liste
          }
          while(rs.next());
        }
        rs.close();
     
      return liste;  // Retourne la liste des fournisseurs ou null s'il n'y en a aucun
     }
     
      public Fournisseur selectParNom(String nom) throws IllegalArgumentException {
        if ("".equals(nom)) { // Si nom est null ou s'il vaut chaine vide, erreur
          System.out.println("Erreur, le nom est obligatoire !");
          throw new IllegalArgumentException("paramètre 'nom' invalide");
        }
        return chargeFournisseur(FOURNISSEUR_SELECT + "where NOM like '" + nom + "%'");
      }
     
      public Fournisseur selectParCPetActivite(String codePostal, String codeActivite) {
        // Vérification sur les paramètres
        ...
        return chargeFournisseur(FOURNISSEUR_SELECT + "where CODE_POSTAL = '" + codePostal + "' AND CODE_ACTIVITE = '"+ codeActivite + "'");
      }
       ...
     
    }
    L'avantage est une bien plus grande flexibilité ([hors sujet]mot à mode ![/hors sujet]).

    En effet les classes qui vont utiliser/appeler tes méthodes de recherche ne changeront pas, même si des modification interviennent sur ta BD.
    Tout ce qu'elles doivent savoir, c'est qu'elle envoient des critères de recherches à une méthode et qu'elles reçoivent une liste d'objets Fournisseur.
    Par exemple, a JListe pourrait être remplie par un accès à SearchFournisseur.selectParCodePostal(unCodePostal)
    Tu pourrais changer ta BD par un fichier XML, qu'elles n'y verrait que du feu ! (-> aucune modif à apporter dans la partie Interface Graphique)

    Enfin, bon voilà en gros comment on peut structurer du code en rendant les classes indépendantes les unes des autres.
    J'espère que tu m'a suivit. C'est vrai que c'est un peu compliqué, mais en réflechissant bien, ça se précise. En tout cas, je pense qu'il est important de bien maîtriser cette notion de découpage en "couches".

  9. #9
    Membre régulier
    Inscrit en
    Juillet 2004
    Messages
    306
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 306
    Points : 122
    Points
    122
    Par défaut
    Bonjour,

    Ok je te remercie pour ton aide.
    Je comprends bien mieux maintenant.

    Je ne te suis pas, ou alors c'est toi qui ne me suis pas !
    C'est exactement ce que fait l'exemple que je t'ai envoyé.
    Le rsToEmploye() est juste là pour alléger la méthode public List chargeEmploye() qui retourne bien une Liste.
    Si tu veux l'appeler executeQuery(), rien ne te l'interdit !
    Oui j'ai bien compris, mais justement ce que je voulais, c t ne pas mettre de méthode rsToEmploye() dans la classe searchFourni. La classe searchFourni crée un objet d'instance ConnectionJDBC, exécute la requête en appelant la méthode executeQuery et récupère les données, sous forme d'une liste ou sous un autre format. Vois-tu ?


    Seule la classe SearchFournisseur doit "connaître" le modèle de données (la table et ses colonnes). Elle servira à "convertir" les données issues des requêtes en objet Fournisseur.
    La classe ConnectionJDBC est chargée de gérer les connections avec la base de donnée, mais ne devrait pas "connaître" le modèle.
    Pour ça, je suis tout à fait d'accord avec toi et pour le reste aussi d'ailleurs.

    Ciao.

  10. #10
    NGY
    NGY est déconnecté
    Membre habitué
    Inscrit en
    Août 2002
    Messages
    137
    Détails du profil
    Informations forums :
    Inscription : Août 2002
    Messages : 137
    Points : 164
    Points
    164
    Par défaut
    De rien et ... bon courage !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Stocker les résultats d'une requête
    Par dam28800 dans le forum Langage
    Réponses: 4
    Dernier message: 14/01/2010, 14h29
  2. Effacer les résultats d'une requête
    Par Nutrino dans le forum Requêtes
    Réponses: 1
    Dernier message: 05/11/2006, 21h54
  3. [SQL] Afficher les résultats d'une requête sur plusieurs pages
    Par mealtone dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 07/09/2006, 13h20
  4. Transformer les résultats d'une requête dans un autre ordre
    Par keikun dans le forum MS SQL Server
    Réponses: 6
    Dernier message: 12/04/2006, 16h29
  5. Limiter les résultats d'une requête à \today\' - n jours
    Par Eddy Duflos dans le forum Langage SQL
    Réponses: 2
    Dernier message: 19/10/2005, 08h46

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo