Statement s'obtient en appelant la méthode
              createStatement() de l'interface 
              Connection.
              
                        Statement.
              
            resultSetType : un entier qui peut prendre les valeurs 
                    TYPE_FORWARD_ONLY, 
                    TYPE_SCROLL_INSENSITIVE et 
                    TYPE_SCROLL_SENSITIVE.
                   
                resultSetConcurrency : un entier qui peut prendre les valeurs 
                    CONCUR_READ_ONLY et 
                    CONCUR_UPDATABLE.
                   
                resultSetHoldability : de même, un entier qui peut prendre les valeurs
                    HOLD_CURSORS_OVER_COMMIT et 
                    CLOSE_CURSORS_AT_COMMIT.
                   
                ResultSet. Nous verrons leur signification exacte dans le paragraphe sur les 
              ResultSet.
              
            Il est important de fermer un 
              Statement lorsqu'il n'est plus utilisé, par appel à sa méthode
              close().
             
          Statement. Chacune de ces méthodes doit être utilisée dans son propre contexte.
              
            executeQuery(String) doit être utilisée si l'exécution du 
                    Statement retourne une liste d'objets (cas d'un 
                    select) ;
                   
                executeUpdate(String) doit être utilisée si l'exécution du 
                    Statement retourne un nombre d'objets modifiés (cas des requête de création, d'effacement ou de mise à jour) ;
                   
                execute(String doit être utilisée si le type de 
                    Statement exécuté n'est pas connu.
                   
                ResultSet. Si la requête SQL passée en paramètre ne correspond pas (par exemple, si elle contient un
                insert), alors une exception de type 
                SQLException est jetée.
                
              
                  Exemple 6. Méthode
                    Statement.executeQuery(String)
                  
                  
                
Statement smt = connection.createStatement() ; ResultSet rs = smt.executeQuery("select nom, prenom from Marins") ; // exploitation du resultat while (rs.hasNext()) { ... }
                  Exemple 7. Méthode
                    Statement.executeUpdate(String)
                  
                  
                
Statement smt = connection.createStatement() ; int count = smt.executeUpdate("insert into Marins(nom, prenom) " + "values ('Robert', 'Surcouf')") ; // exploitation du resultat if (count > 0) { ... }
true si l'objet retourné est de type
                ResultSet et 
                false s'il s'agit d'un entier. On peut ensuite obtenir ces objets en appelant les méthodes
                getResultSet() et 
                getUpdateCount().
                
              De plus, si l'exécution de cette requête a généré plusieurs résultats, la méthode
                getMoreResult() doit être appelée. Voyons l'utilisation de toute ceci.
                
              
                  Exemple 8. Méthode
                    Statement.execute(String)
                  
                  
                
Statement stmt = conn.createStatement() ; boolean returnedValue = smt.execute(sql) ; // on ne connaît pas la nature // de cette requête ResultSet rs ; int count ; do { if (returnedValue) { // le résultat est un result set rs = stmt.getResultSet(); // exploitation du result set ... } else { // le résultat est un entier count = stmt.getUpdateCount() ; if (count == -1) { // une valeur -1 indique qu'il n'y a plus de résultat à exploiter break ; // sortie du while } else { // exploitation du count ... } } returnedValue = smt.getMoreResult() ; } while (true) ;
resultSet par appel à la méthode 
                getResultSet() ferme automatiquement l'ancien. Ce comportement peut être changé, si le pilote utilisé le permet, comme nous le verrons dans le paragraphe sur les 
                ResultSet.
               
            Statement doivent être fermés par un appel à la méthode 
              close() une fois qu'ils ne sont plus utilisés. La fermeture d'un
              Statement entraîne automatiquement la fermeture de tous les objets
              ResultSet qui ont été ouverts sur ce 
              Statement.
              
            Notons que même si la fermture d'une connexion (par appel à sa méthode
              close()) ferme automatiquement tous les 
              Statement ouverts dessus, il est recommandé de le faire à la main. De même que pour la fermeture des
              ResultSet.
              
            Une fois qu'un objet 
              Statement ou 
              ResultSet a été fermé, il est illégal d'invoquer une de ses méthodes. L'appel d'une telle méthode peut jeter systématiquement une exception de type 
              SQLException.
             
          PreparedStatement étend l'interface 
              Statement, donc tout ce qui précède et qui concerne l'interface
              Statement reste valide pour l'interface 
              PreparedStatement.
              
            L'interface 
              PreparedStatement ajoute la possibilité de paramétrer des requêtes SQL. Les instances de
              PreparedStatement s'utilisent quand une même requête doit être exécutée plusieurs fois, avec des paramètres différents. La chaîne de caractères SQL contient donc des marqueurs, qui seront remplacés par des valeurs à chaque exécution.
              
            On préfèrera systématiquement l'utilisation de
              PreparedStatement aux 
              Statement classiques, en particulier pour les requêtes de mise à jour. Ces requêtes comportent le plus souvent des paramètres, qu'il faut ajouter à la chaîne de caractères SQL à exécuter. Utiliser des
              PreparedStatement permet de passer par les méthodes de paramétrage du pilote de base, ce qui nous décharge de la délicate gestion des erreurs, et évitera les attaques par injection de code SQL.
              
            PreparedStatement se crée de la même façon qu'un
                Statement normal.
                
              
                  Exemple 9. Création d'un
                    PreparedStatement
                  
                  
                
PreparedStatement ps = conn.prepareStatement(
    "insert into Marins (nom, prenom, age) values (?, ?, ?)") ;
                Statement normal, on peut passer des options lors de la création d'un
                PreparedStatement.
                
              On remarque la présence de trois caractères
                ? dans la chaîne SQL passée en paramètre. Ce sont ces caractères qui doivent être remplacés par des valeurs afin de pouvoir exécuter la requête SQL proprement dite.
               
            PreparedStatement propose un jeu de méthode
                set<Type>(int, Type) : 
                setInt(int, int), 
                setFloat(int, float), 
                setString(int, String), etc... Chacune de ces méthodes peut être appelée pour fixer la valeur d'un paramètre donné.
                
              
                  Exemple 10. Fixer les paramètres d'un
                    PreparedStatement
                  
                  
                
PreparedStatement ps = conn.prepareStatement(
    "insert into Marins (nom, prenom, age) values (?, ?, ?)") ;
ps.setString(1,  "Surcouf") ;
ps.setString(2,  "Robert") ;
ps.setInt(3,  32) ;
                SQLException.
                
              On peut effacer la valeur de tous les paramètres d'un
                PreparedStatement en appelant la méthode
                clearParameter().
               
            null nécessite l'utilisation d'une méthode particulière :
                setNull(int, int). Cette méthode prend deux paramètres :
                
              java.sql.Types
                     
                  
                  Exemple 11. Positionner un paramètre à
                    null
                  
                  
                
PreparedStatement ps = conn.prepareStatement(
    "insert into Marins (nom, prenom, age) values (?, ?, ?)") ;
ps.setString(1,  "Surcouf") ;
ps.setString(2,  "Robert") ;
ps.setNull(3, java.sql.Types.INTEGER) ;
                PreparedStatement se déroule de la même manière que pour un
              Statement, à l'aide des trois méthodes 
              executeQuery(), 
              executeUpdate() et 
              execute().
              
            PreparedStatement propose deux méthodes :
                
              getMetaData() : retourne un objet 
                      ResultSetMetaData, qui contient des informations sur les colonnes retournées par la requête SQL ;
                     
                  getParameterMetaData() : retourne un objet 
                      ParameterMetaData, qui contient des informations sur les paramètres déclarés dans ce
                      PreparedStatement.
                     
                  getMetaData() retourne un objet de type 
                ResultSetMetaData qui propose un jeu d'une vingtaine de méthodes pour déterminer le types de colonnes du résultat de la requête. Voyons ceci sur un exemple.
                
              
                  Exemple 12. Utilisation d'un objet
                    ResultSetMetaData
                  
                  
                
// on ne connaît pas les colonnes du résultat de cette requête PreparedStatement pstmt = conn.prepareStatement("select * from Marins where id = ?") ; ResultSetMetaData rsmd = pstmt.getMetaData() ; // lecture du nombre de colonne int columnCount = rsmd.geColumnCount() ; for (int i = 1 ; i <= columnCount ; i++) { int columnType = rsmd.getColumnType(i) ; // label de la colonne String columnLabel = rsmd.getColumnLabel(i) ; // nom de la colonne String columnName = rsmd.getColumnName(i) ; }
getParameterMetaData() retourne un objet de type 
                ParameterMetaData, qui lui-même propose quelques méthodes pour obtenir des informations sur les paramètres d'un
                PreparedStatement. Voyons un exemple d'utilisation.
                
              
                  Exemple 13. Utilisation d'un objet
                    ParameterMetaData
                  
                  
                
// on ne connaît pas les colonnes du résultat de cette requête PreparedStatement pstmt = conn.prepareStatement("select * from Marins where id = ?") ; ParameterMetaData pmd = pstmt.getParameterMetaData() ; // lecture du nombre de colonne int parameterCount = pmd.geParameterCount() ; for (int i = 1 ; i <= parameterCount ; i++) { // type du paramètre (une constante de java.sql.Types) int parameterType = pmd.getColumnType(i) ; // mode du paramètre int parameterMode = pmd.getParameterMode(i) ; }
IN, 
                OUT ou 
                INOUT est utilisé pour les
                CallableStatements.
               
            
                Exemple 14. Méthode
                  getGeneratedKeys()
                
                
              
Statement stmt = connection.createStatement() ; // le paramètre RETURN_GENERATED_KEYS va nous permettre de récupérer // la clé générée par MySQL int rowCount = smt.executeUpdate( "insert into Marins (nom, prenom) values ('Surcouf', 'Robert')", Statement.RETURN_GENERATED_KEYS) ; ResultSet rs = stmt.getGeneratedKeys(); if (rs.next()) { // récupération de la clé primaire int idSurcouf = rs.getInt(1) ; }
Statement et de les exécuter en une seule fois. On appelle ce genre d'exécution
              
                l'exécution en batch
              . En général cela signifie que l'on s'attend à ce que l'exécution totale soit assez longue, et que pendant ce temps, le système peut faire autre chose.
              
            L'exécution de commandes SQL en batch n'est possible que pour des requêtes de modification de la base, celles que l'on exécute avec la méthode
              executeUpdate(String). Toute requête SQL qui peut être exécutée de la sorte, peut également être passée en paramètre de la méthode
              addBatch(String). L'appel de cette méthode ne fait que stocker la requête SQL, sans l'exécuter. C'est l'appel à la méthode
              executeBatch() qui déclenche l'exécution.
              
            L'exécution en batch peut représenter des gains substantiels en performances. Le coût d'une aller et retour avec la base de données est en lui-même coûteux, et l'on tentera le plus possible de minimiser ces allers et retours.  
            Statement.
                
              
                  Exemple 15. Exécution d'un
                    Statement en batch
                  
                  
                
// l'exécution en batch doit se faire en mode non auto-commit connection.setAutoCommit(false) ; Statement smt = connection.createStatement() ; smt.addBatch("insert into Marins(nom, prenom) values ('Surcouf', 'Robert')) ; smt.addBatch("insert into Marins(nom, prenom) values ('Tabarly', 'Eric')) ; ... // lancement de l'exécution de toutes nos insertions int [] updateCounts = smt.executeBatch() ;
executeBatch() d'annuler la transaction et de remettre la base dans l'état initial.
               
            PreparedStatement. Le mécanisme est toutefois légèrement différent, puisqu'un
                PreparedStatement est construit sur une unique requête SQL paramétrée.
                
               
                PreparedStatement propose une méthode
                addBatch() qui ne prend aucun paramètre. Au moment où cette méthode est appelée, JDBC construit une requête SQL avec la requête du
                PreparedStatement, et le jeu de paramètres qu'il a à sa disposition. Si l'un des paramètres n'a pas été fixé, une erreur est générée. On peut ainsi ajouter autant de requêtes que l'on veut.
                
              L'exécution des requêtes se fait de la même manière et sous les mêmes contraintes que pour un
                Statement classique.
                
              
                  Exemple 16. Exécution d'un
                    PreparedStatement en batch
                  
                  
                
// l'exécution en batch doit se faire en mode non auto-commit connection.setAutoCommit(false) ; PreparedStatement psmt = connection.prepareStatement("insert into Marins(nom, prenom) " + "values (?, ?)") ; psmt.setParameter(1, "Surcouf") ; psmt.setParameter(2, "Robert") ; // ajout d'une requête avec les paramètres ('Surcouf', 'Robert') psmt.addBatch() ; psmt.setParameter(2, "Pierre") ; // ajout d'une requête avec les paramètres ('Surcouf', 'Pierre') psmt.addBatch() ; psmt.setParameter(1, "Tabarly") ; psmt.setParameter(2, "Eric") ; // ajout d'une requête avec les paramètres ('Tabarly', 'Eric') psmt.addBatch() ; ... // lancement de l'exécution de toutes nos insertions int [] updateCounts = smt.executeBatch() ;