Université Unive rsité de Nice - Sophi Sophiaa Anti Antipolis polis Richard Grin Version Versio n 3.1 – 16/8/07 16/8/07
JDBC (Java Data Base Connectivity) permet l'accès à des bases de données avec le langage SQL, depuis un programme en Java Il est fourni par le paquetage java.sql L’API JDBC est presque totalement indépendante des SGBDs (quelques méthodes ne ne peuvent être être utilisées qu’avec certains certains SGBDs mais ne doivent être utilisées qu’en cas de nécessité impérieuse pour améliorer les performances)
R. Grin
Versions de SQL supportées Les premières versions de JDBC supportent le standard SQL-2 Entry Level JDBC 2 et 3 offrent en plus des fonctionnalités de SQL3 Pour des raisons d'efficacité un driver peut utiliser les possibilités particulières d'un SGBD (c'est permis par JDBC), mais au détriment de la portabilité JDBC 4 accompagne Java 6 ; il utilise les annotations et apporte plus de facilités pour l’écriture du code JDBC
page 2
Contenu de java.sql
R. Grin
JDBC
page 3
Ce paquetage contient un grand nombre d'interfaces et quelques classes Les interfaces constituent l’interface de programmation JDBC ne fournit pas les classes qui implantent les interfaces
R. Grin
JDBC
page 4
Drivers
Types de drivers
Pour travailler avec un SGBD il faut disposer de classes qui implantent les interfaces de JDBC Un ensemble de telles classes est désigné sous le nom de driver JDBC Les drivers dépendent du SGBD auquel ils permettent d'accéder Tous les SGBD importants importants du marché ont un (et même plusieurs) driver JDBC, fourni par l'éditeur du SGBD ou par des éditeurs de logiciels indépendants
Type 1 : pont JDBC-ODB JDBC-ODBC C Type 2 : driver driver qui fai faitt appel à des fon fonction ctionss natives non Java (le plus souvent en langage C) de l'API du SGBD que l'on veut utiliser Type 3 : driver qui permet l'utilisation d'un serveur
R. Grin
JDBC
page 5
middleware
Type 4 : driver écrit entièrement entièrement en Java, qui utilise le protocole réseau du SGBD
R. Grin
JDBC
page 6
1
Type 2 : utilise une API native
Type 1 : pont JDBC-ODBC Application Java
Application Java
Driver JDBC
(en Java)
Driver ODBC
(pas en Java)
Les méthodes du driver JDBC font font appel à des
Partie en Java
fonctions d'une API du SGBD écrite dans un autre langage que Java
Les méthodes du driver JDBC font appel à des fonctions en langage C d'un driver ODBC
SGBD
JDBC
page 7
Type 3 : accès accès à un serv serveur eur middleware
R. Grin
JDBC
direct auApplication SGBDJava
Driver en Java
Driver en Java
Protocole du serveur middleware Serveur middleware
Les méthodes du driver JDBC utilisent des sockets pour dialoguer avec le SGBD selon son protocole réseau
Protocole du SGBD
SGBD R. Grin
JDBC
page 8
Type 4 : 100 % Java avec accès
Application Java
Les méthodes du driver JDBC se connectent par socket au serveur middleware et lui envoient les requêtes SQL ; le serveur middleware les traitent en se connectant au SGBD
Driver
Protocole du SGBD
SGBD
R. Grin
(en Java) (pas en Java)
Partie native
SGBD page 9
Types de drivers et applet untrusted Une applet ne peut pas charger à distance du code natif (non Java) ; elle ne peut donc pas utiliser les drivers de type 1 et 2 Pour des raisons de sécurité, une applet untrusted (qui fonctionne dans le bac à sable ; voir cours sur la sécurité) ne peut échanger des données par sockets qu'av qu'avec ec la machine d'où elle provient, ce qui implique des contraintes avec les drivers de type 3 et 4
R. Grin
JDBC
pa ge 10
Driver de type 3 et applet untrusted Le serveur middleware doit être sur la même machine que le serveur HTTP
Code Java Applet Driver en Java connexion par socket
Serveur HTTP
Serveur middleware
SGBD R. Grin
JDBC
page 11
R. Grin
JDBC
pa ge 12
2
Driver de type 4 et applet untrusted Code Java Le serveur HTTP doit être sur la même machine que le SGBD
Applet
Driver en Java
Travailler avec JDBC connexion par socket
Serveur HTTP
R. Grin
SGBD
JDBC
page 13
R. Grin
Pour utiliser JDBC A l’exécution, ajouter le chemin des classes du (des) driver dans le classpath (option -classpath de la commande java) Par exemple, si Oracle est installé dans /oracle, le driver peut être dans le fichier /oracle/jdbc/lib/ojdbc14.jar
et l’application sera lancée par la commande
Importer le paquetage java.sql (et java.mat h si on utilise la classe BigDecimal ) : import java.sql.*;
Charger en mémoire la classe du (des) driver (driver de type 4 fourni par Oracle pour cet exemple) avant d'utiliser JDBC : Class.forName("oracle.jdbc.OracleDriver");
Étapes du travail avec une base de données avec JDBC 1. Ouvrir une connexion (Connection) 2. Créer des instructions SQL (Statement, PreparedStatement ou CallableStatement ) 3. Lancer l'exécution de ces instructions : n n n
Classes et interfaces de JDBC
interroger la base (executeQuery()) ou modifier la base (executeUpdate()) ou tout autre ordre SQL (execute())
4. Fermer la connexion ( close()) R. Grin
JDBC
page 17
R. Grin
JDBC
pa ge 18
3
Avertissement Dans la suite du cours on utilise des raccourcis tels que « insta instance nce de Connection » Comme Connection est une interface, il faut
Nous étudierons tout d'abord les classes et méthodes de base de JDBC Des nouvelles possibilités de JDBC 2 et 3, en
traduire par «Connection instance d’une implémente » classe qui
particulier sont à SQL3, seront abordées abordé es dans dcelles ans les lequi s par parties tiesliées « JDBC avancé » et « JDBC et objet-relat objet-relationnel ionnel »
R. Grin
JDBC
page 19
R. Grin
JDBC
pa ge 20
Interfaces principales
Classes principales
Driver : renvoie une instance de Connection Conne Connection ction : connexion connexion à une base base Stat Statement ement : ordre SQL PreparedStatement : ordre SQL paramétré CallableStatement : procédure stockée stockée sur le SGBD ResultSet : lignes récupérées récupérées par un ordre ordre SELECT ResultSetMetaData : description des lignes récupérées par un SELECT DatabaseMetaData : informations sur la base de données
DriverManager : gère les drivers, lance les connexions aux bases Date : dat datee SQL Time : heures, minutes, secondes SQL TimeS TimeStamp tamp : date et heu heure, re, ave avecc une précisi précision on à la microseconde Types : constantes pour désigner désigner les types SQL (pour les conversions avec les types Java)
R. Grin
JDBC
page 21
R. Grin
JDBC
pa ge 22
Exceptions de JDBC 4 (1)
Exceptions SQLException SQLExcepti on : erreurs SQL SQLWarning : avertissements SQL (classe fille de SQLException) ; le mécanisme de récupération des avertissements est est étudié plus loin DataTruncation : avertit quand une une valeur est tronquée lors d'un transfert entre Java et le SGBD (classe fille de SQLWarning)
a 3 sous-classes pour distinguer différents types d’exception SQLNonTransientException : le problème ne peut être résolu sans une action externe ; inutile de réessayer la même action sans rien faire de spécial SQLTransientException : le problème peut avoir été résolu si on attend un un peu avant de ressayer SQLRecoverableException : l’application peut résoudre le problème en exécutant une certaine action SQLException n
n
n
R. Grin
JDBC
page 23
R. Grin
JDBC
pa ge 24
4
Exceptions de JDBC 4 (2)
Chaînage des exceptions
Classes filles de SQLNonTransientException : SQLDataException , SQLFeatureNotSupportedException ,
Une requête SQL peut provoquer plusieurs exceptions On peut obtenir la prochaine exception par la
getNextException() méthode Une exception peut avoir une cause ; on l'obtient par la méthode getCause() Toutes ces exceptions peuvent être parcourues par une bou boucle cle « for for-ea -each ch » :
Classes filles de SQLTransientException : SQLTimeoutException , SQLTransactionRollbackException ,
catch(SQLE catch( SQLExce xcepti ption on ex) { for for ( (Th Thro rowa wabl ble e e : ex) { … }
SQLTransientConnectionException R. Grin
JDBC
R. Grin
page 25
La méthode connect() de Driver prend en paramètre un URL et renvoie une instance de l'interface Connection Cette instance de Connection permettra de lancer des requêtes vers le SGBD connect renvoie null si le driver ne convient pas pour se connecter à la base désignée par par l'URL
JDBC
Un URL pour une base de données est de la forme : jdbc:sous-protocole:base de donnée Par exemple, pour Oracle : jdbc:oracle:thin:@sirocco.unice.fr:1521:INFO jdbc:oracle:thin:@sirocco.uni ce.fr:1521:INFO oracle:thin est le sous-protocole (driver (driver « thin » ; Oracle fournit aussi un autre type de driver) @sirocco.unice.fr:1521:INFO @sirocco.unice.fr:1521 :INFO désigne la base de données INFO située sur la machine sirocco (le ( le serveur du SGBD écoute sur le port 1521) La forme exacte des parties sous-protocole et base de données dépend du SGBD cible n
n
Utilisée par DriverManager DriverManager ; pas visible par l’utilisateur de l’API
R. Grin
page 27
R. Grin
JDBC
pa ge 28
JDBC 4 et le driver
Gestionnaire de drivers La classe DriverManager gère les drivers (instances de Driver) disponibles pour les différents SGBD utilisés par le programme Java Pour qu'un driver soit utilisable, on doit charger sa classe en mémoire :
Class.forName("oracle.jdbc.OracleDriver");
pa ge 26
URL d'une base de données
Interface Driver
JDBC
La classe crée alors une instance d'elle même et enregistre cette instance auprès de la classe
JDBC 4 utilise un autre mécanisme pour charger le driver : il suffit d'indiquer le nom de la classe du driver dans un fichier META-INF/s METAINF/service ervices/jav s/java.sql a.sql.Drive .Driverr distr distribué ibué avec le driver JDBC Il est alors inutile d’appeler la méthode
Class.forName
DriverManager
R. Grin
JDBC
page 29
R. Grin
JDBC
pa ge 30
5
Obtenir une connexion
Connexions et threads
Pour obtenir une connexion connexion à un SGBD, on demande cette connexion connexion à la classe gestionnaire de drivers : static final static final Strin String g url = "jdbc:oracle:thin:@sirocco.unice.fr:1521:INFO"; Conn Connec ecti tion on co conn nn = DriverManager.getConnection(url, "toto", "mdp");
La classe DriverManager s'adre s'adresse sse à tour de rô rôle le à tous les drivers qui se sont enregistrés (méthode connect), jusqu'à ce qu'un driver lui fournisse une connexion (ne renvoie pas null) R. Grin
JDBC
page 31
Les connexions sont des ressources coûteuses, et surtout surtout longues à obten obtenir ir On peut donc être être tenté de les réutiliser dans
threads plusieurs Mais, attention, lesdifférents connexions ne peuvent être partagées par plusieurs threads À la place, utiliser utiliser les pools de connexions fournis avec les « sources sources de donnée donnéess » (étud (étudiées iées ddans ans une autre partie du cours)
R. Grin
Transactions
JDBC
pa ge 32
Niveau d’isolation
Par défaut la connexion est en « auto-commit » : un commit est automatiquement automatiquement lancé après chaque ordre SQL qui modifie la base Le plus souvent il faut enlever l'auto-commit :
Le niveau d’isolation d’une transaction peut être modifié modifi é: conn.setTransactionIsolation( Connection.TRANSACTION_SERIALIZABLE) ;
conn.setAutoCommit(false)
Il faut alors explicitement valider ou annuler la transaction par n
conn.commit()
n
conn.rollback()
R. Grin
JDBC
page 33
R. Grin
JDBC
pa ge 34
Exécution de l’instruction SQL simple
Instruction SQL simple Instance de l'interface Statement La création est effectuée par la méthode createStatement() de Connection :
La méthode à appeler dépend de la nature nature de l'ordre SQL que l’on veut exécuter : consultation (select) : executeQuery() renvoie un ResultSet pour récupérer les lignes lignes une à une modification des données (update, insert, delete) ou ordres DDL (create table,…) : executeUpdate() renvoie le nombre de lignes modifiées si on ne connaît pas pas à l'exécution la nature de l'ordre SQL à exécuter ou si l'ordre peut renvoyer plusieurs résultats : execute() n
Statemen Stat ement t stmt stmt = connexi connexion. on.cre create ateSta Stateme tement() nt(); ;
n
n
R. Grin
JDBC
page 35
R. Grin
JDBC
pa ge 36
6
Interface ResultSet
Consultation des données (SELECT)
executeQuery() ResultSet
ResultSet
Statem Sta tement ent stmt stmt = conn.cre conn.create ateStat Statemen ement() t(); ; // rset contie contient nt les lignes lignes renvoyées renvoyées Re Resu sult ltSe Set t rset rset =
renvoie une instance de
va permettre de parcourir toutes les lignes renvoyées par le select
stmt.executeQuery("SELECT nomE FROM emp");
// On récupère récupère c chaque haque ligne ligne une à une while whi le (rset. (rset.next next()) ()) System.out.p System .out.println rintln (rset.getStri (rset.getString(1)); ng(1)); // ou . . . (rset.getString("nomE")); stmt.close();
La première colonne a le numéro 1
Voir plus loin le transparent sur la R. fermeture Grin des ressources
JDBC
page 37
ResultSet est positionné Au début,ligne posit ionné avant première et il faut donc commencer parlale faire avancer à la première ligne en appelant appelant la méthode next() Cette méthode permet de passer passer à la ligne suivante ; elle renvoie true si cette ligne suivante existe et false sinon R. Grin
Interface ResultSet
n
n
colonne, pas préfixé par un nom de table ; dans le cas d’une jointure utiliser un alias de colonne)
XXX désigne le type Java de la valeur v aleur que l'on va récupérer, par exemple String, Int ou Double Par exemple, getInt renvoie un int
JDBC
pa ge 38
ResultSet Result Set - perfor performance mancess
Quand ResultSet est positionné positionné sur une ligne les méthodes getXXX getXXX permettent de récupérer les valeurs des colonnes de la ligne : getXXX(int numéroColonne) getXXX(String nomColonne) (nom simple d’une
R. Grin
JDBC
page 39
Quand le réseau est lent et que l’on veut récupérer de nombreuses lignes, il est parfois possible d’améliorer sensiblement les performances en modifiant le nombre de lignes récupérées à chaque fois par le ResultSet (il faut effectuer des tests pour chaque cas) Pour cela, on utilise la méthode setFetchSize de Statement C’est seulement une indication qu’on donne au driver ; il n’est pas pas obligé d’en tenir compte
R. Grin
Types JDBC/SQL
JDBC
pa ge 40
Types JDBC/SQL (classe Types)
Tous les SGBD n'ont pas les mêmes types SQL ; même les types de base peuvent présenter des différences importantes Pour cacher ces différences, JDBC définit ses propres types SQL dans la classe Types, sous forme de constantes nommées Ils sont utilisés par les programmeurs quand ils doivent préciser un type SQL (setNull , setObject , registerOutParameter ) Le driver JDBC fait la traduction de ces types dans les types du SGBD
Correspondances entre types Java et SQL Il reste le problème de la correspondance entre les types Java et les types SQL Dans un programme JDBC, les méthodes getXXX, setXXX setXX X servent servent à préciser préciser cette corre correspond spondance ance Par exemple, getString indique que l’on veut récupérer la donnée SQL dans une String C'est le rôle du driver particulier à chaque SGBD de faire les traductions correspondantes ; une exception peut être lancée si ça n’est pas possible
R. Grin
JDBC
On a une grande latitude ; ainsi, presque tous les types SQL peuvent être retrouvés par getString() Cependant, des méthodes sont recommandées ; voici des exemples :
page 43
n
n
n n n
CHAR et VARCHAR VARCHAR : getString, getString, LONGVA LONGVARCHAR RCHAR : getAsciiStream et getCharacterStream BINARY BINAR Y et VARBIN VARBINARY ARY : getByt getBytes, es, LONGVARB LONGVARBINARY INARY : getBinaryStream REAL : getFloat, oat, DOUBLE DOUBLE et FLOA FLOAT T : getDouble getDouble DECIMAL DECIM AL et NUMERIC NUMERIC : getBigDecim getBigDecimal al DATE : getDa getDate, te, TIME TIME : getTime, getTime, TIMEST TIMESTAMP AMP : getTimestamp
R. Grin
Types Date en Java et en SQL java.sql contient une classe Date qui est utilisé par JDBC pour les échanges de dates entre Java et la base de données Cette classe hérite de la classe java.util.Date Elle correspond à un temps en millisecondes Normalement les dates SQL ne contiennent pas d’indication sur l’heure dans la journée ; il faut utiliser les types SQL TIME et TIMESTAMP pour l’heure dans la journée Pour passer de java.util.Date à java.sql.Date , utiliser la méthode getTime() JDBC
page 45
Pour passer de java.util.Date à java.sql.Date , utiliser la méthode getTime() : java.util.Da java.u til.Date te date = new java java.util.D .util.Date(); ate(); java java.s .sql ql.D .Dat ate e dateS dateSQL QL = new java.sql.Date(date.getTime()); java.s jav a.sql. ql.Tim Time e time = new Time(date.getTime()); java.s jav a.sql. ql.Tim Timesta estamp mp tim time e = new Timestamp(date.getTime());
R. Grin
n
java.text.DateFormat
calculs sur les dates avec la classe java.util.Calendar
Voir le cours sur les dates dans le support « Com Complé plémen ments ts di divers vers »
R. Grin
JDBC
pa ge 46
Statem Sta tement ent stmt = conn. conn.cre create ateStat Statemen ement() t(); ; ResultSet rs ResultSet rset et = stmt stmt.execu .executeQuery teQuery( ( "SELECT "SELEC T no nomE, mE, c comm omm FROM emp"); while whi le (rs (rset. et.next next()) ()) { nom = rset.getString("nomE"); commission = rset.getDouble("comm"); if (rset.wasNull()) System.out.println(nom + ": pas de comm"); else System.out.println(nom + " a " + commission + " € de co commi mmissi ssion" on"); ); }
Un petit rappel sur les dates en Java J ava : mise en forme avec la classe n
JDBC
Valeur NULL NULL
Manipulation des dates
pa ge 44
Exemple
R. Grin
JDBC
page 47
R. Grin
JDBC
pa ge 48
8
Modification des données (INSERT, UPDATE, DELETE)
Instruction SQL paramétrée
Statem Sta tement ent stmt = conn.crea conn.createSt teState atemen ment() t(); ; String ville = "NICE"; int nbLignes nbLignesMod Modifi ifiees ees = stmt.ex stmt.execu ecuteU teUpda pdate( te( "INSERT "INSER T INTO dept dept (dept, nomD, nomD, lieu) lieu) " + "VALUES (70, 'DIRECTION'," + "'" + ville + "')"); stmt.close();
R. Grin
N'oubliez pas l'espace !
JDBC
page 49
La plupart des SGBD (dont Oracle) peuvent n'analyser qu'une seule fois une requête exécutée un grand nombre de fois durant une
connexion JDBC permet de profiter de ce type de fonctionnalité par l'utilisation de requêtes paramétrées ou de procédures stockées Les requêtes paramétrées sont associées aux instances de l'interface PreparedStatement PreparedStatement qui hérite de l'interface Statement
R. Grin
Les "?" indiquent les emplacements des paramètres Cette requête pourra être exécutées avec plusieurs couples de valeurs : (2500, ‘DUPOND’), (3000, ‘DURAND’), etc.
R. Grin
JDBC
page 51
Les valeurs des paramètres sont données par les méthodes setXXX(n, valeur) On choisit la méthode setXXX suivant le type Java de la valeur que l'on veut v eut mettre dans la base de données C'est au programmeur de passer une valeur Java J ava du bon type type à la métho méthode de setXXX setXXX Le driver JDBC fait la conversion dans le bon format pour le SGBD
R. Grin
Pr Prep epar ared edSt State ateme ment nt ps pstm tmt t = conn.prepareStatement(
"UPDATE "UPD ATE emp emp SET sal sal = ? " for (int (int i=0 i=0; ; i<10; i<10; i++) i++) {
JDBC
pa ge 52
Requête paramétrée - NULL NULL
Requêtee para Requêt paramétrée métrée - Exemple Exemple
+ "WHERE nomE = ?");
pa ge 50
Requête paramétrée – Valeurs des paramètres
Création d'une requête paramétrée Pr Prep epar ared edSta State teme ment nt ps pstm tmt t = conn.prepareS conn.p repareStateme tatement("UPD nt("UPDATE ATE emp SET sal = ?" + " WHERE nome = ?");
Pour passer la valeur NULL NULL à la base de donnée, on peut utiliser la méthode setNull(n, type) (type de la classe Types) ou passer la valeur Java null si la méthode setXXX() attend un objet en paramètre n
n
pstmt.executeUpdate(); }
R. Grin
JDBC
page 53
R. Grin
JDBC
pa ge 54
9
Avantages des PreparedStatement Leur traitement est plus rapide s’ils sont utilisés plusieurs fois avec plusieurs paramètres Ils améliorent aussi aussi la portabilité car les méthodes setXXX gèrent les différences entre SGBD
Procédures stockées
En effet,de lesdate SGBD n’utilisent pas les mêmes formats ( JJ/MM/AA ou tous AAAA-MM-JJ par exemple) ou de chaînes de caractères c aractères (pour les caractè caractères res d’« d’« échappement échappement ») Mais on peut aussi utiliser pour cela la syntaxe (un peu peu lour lourde) de) « SQL Escape Escape » (voir plus loin) loin) Ils évitent l'injection de code SQL R. Grin
'
'
JDBC
'
'
page 55
Comme les accès réseau auxles bases de données ralentissent les applications, procédures stockées permettent souvent d’améliorer les performances Mais elles nuisent aussi souvent à la portabilité des applications R. Grin
Exemple de procédure stockée (Oracle) create or replace create replace proced procedure ure augmen augmenter ter (unDept (unDep t in intege integer, r, pourcentage pourcentage in number, number, cout out number) is begin select sum(sal) * pourcentage / 100 into into cou out t fro m em p wher where e dept dept = u unD nDep ept; t; update emp set sal = sal * (1 + pourcentage / 100) wher where e dept dept = u unD nDep ept; t; end; R. Grin
JDBC
page 57
Les procédures stockées permettent non seulement de précompiler des ordres SQL mais aussi de les regrouper
La syntaxe de l'appel des procédures stockées n'est pas standardisée ; elle diffère suivant les SGBD JDBC utilise sa propre syntaxe pour pallier ce problème : si la procédure renvoie une valeur : Le driver { ? = call nom-procédure(?, ?,...) ?,...) } traduira si elle ne renvoie aucune valeur : dans la { call nom-procédure(?, ?,...) } syntaxe du SGBD si on ne lui passe aucun paramètre : { call nom-procédu nom-procédure re }
pa ge 56
Création d'une procédure stockée Les procédures stockées sont associées aux instances de l'interface l'interface CallableStatement CallableStatement qui hérite de l'interface PreparedStatement La création d'une instance de CallableStatement se fait par l'appel de la méthode prepareCall de la classe Connection On passe à cette méthode une chaîne chaîne de caractères qui décrit comment sera appelée la procédure stockée, et si la procédure renvoie une valeur ou non
R. Grin
Syntaxe pour les procédures stockées
JDBC
JDBC
pa ge 58
Exemple Call Callab ableS leSta tate teme ment nt cstm cstmt t = conn.prepareCall("{? = call augmenter(?,?)}");
n
n
n
R. Grin
JDBC
page 59
R. Grin
JDBC
pa ge 60
10
Lancement d'une procédure stockée L'appel de la procédure L'appel procédure est précédé précédé du passag passage e à la pro procéd cédure ure des par paramè amètre tress « in » et « in/out in/out » par les méthodes setXXX() (idem requêtes paramétrées) On doit doit indiquer indiquer le type ddes es para paramètre mètress « out » et « in/ou in/outt » par la m métho éthode de reg register isterOutPa OutParamete rameter() r() Ensuite on lance la procédure par une des méthodes executeQuery(), executeUpdate() ou execute(), suivant le type des commandes SQL que la procédure contient c ontient On récu récupèr pèree le less pa param ramètr ètres es « out » et « in/out in/out » par les méthodes getXXX() (idem requêtes paramétrées)
R. Grin
JDBC
page 61
Utilisation d'une procédure stockée CallableS Callab leStat tatemen ement t csm csmt t = con conn.pr n.prepar epareCa eCall( ll( "{ call augmenter(?, ?, ?) }"); // 2 chiffres après la virgule pour 3ème paramètre
csmt.registerOutParameter(3, Types.DECIMAL, 2); // Augmentation de 2,5 % des des salaires du dept 10
csmt.setInt(1, 10); csmt.setDouble(2, 2.5); csmt.executeQuery(); // ou execute() double cout = csmt.getDouble(3); System.out.println("Cout total augmentation : " + cout); R. Grin
Procédures stockées contenant
plusieurs ordres SQL Une procédure stockée peut contenir plusieurs
On peut ne pas savoir quels ordres SQL sont contenus dans une procédure stockée Dans ce cas, on utilise le fait que n n
Statement
n
Ainsi, si elle contient 2 ordres SELECT, on récupère le 1er ResultSet par getResultSet ; on passe à la 2ème requête par getMoreResults et on récupère son ResultSet par getResultSet
R. Grin
JDBC
page 63
Schéma de code
JDBC
execute renvoie execute renvoie true true si le 1er résultat est un ResultSet getMoreResults renvoie true si le résultat suivant est un ResultSet getUpdateCount() : renvoie le nombre de lignes modifiées, ou -1 s'il n'y a plus de résultat (ou si le résultat est un ResultSet)
On peut exécuter tous les ordres dans une boucle dont la condition de fin est !getMoreResults() && getUpdateCount() == -1
R. Grin
JDBC
pa ge 64
Renvoyer un ResultSet d’une procédure stockée avec Oracle
boolean retval = cstmt.execute(); do { if (retval (retval == false) false) { // pas un ResultSet ResultSet int coun count t = cstmt.getU cstmt.getUpdate pdateCoun Count(); t(); if (count == -1) break; // c’est fini ! else { // tra traite ite l’ordre l’ordre SQ SQL L . . . } } else else { // Res Result ultSet Set ResultSet Resul tSet rs = cstmt.getResul cstmt.getResultSet( tSet(); ); . . . // traite le ResultSet } retval retva l = cstmt.get cstmt.getMoreR MoreResult esults(); s(); while while (true) (true); ; R. Grin
pa ge 62
Ordre SQL quelconque
ordres SQL de divers types Pour retrouver tous les résultats de ces ordres (ResultSet ou nombre de lignes modifiées), on utilise la méthode getMoreResults() de la classe
JDBC
Attention, les 4 transparents qui suivent sur ce sujet sont particuliers particuliers à Oracle ; consultez consultez le manuel de votre SGBD si vous travaillez avec un autre SGBD Il faut faut utili utiliser ser le le type type « ref cursor » d’Ora d’Oracle cle eett des extensions JDBC fournies avec le driver distribué par Oracle Le curseur Oracle Oracle sera fermé quand l’instance de CallableStatement sera fermée
page 65
R. Grin
JDBC
pa ge 66
11
Créer le type référence de curseur
Fonction qui renvoie un curseur 1.
Il faut Créer un type pour la référence de curseur qu’on va renvoyer
2.
Créer la fonction qui renvoie la référence de curseur
R. Grin
JDBC
Créer un nom de type pour la référence de curseur qu’on va renvoyer Pour utiliser ensuite le type, il faut le créer dans un
paquetage create or :rep create replac lace e pack package age Typ Types es AS type curseur curseur_type _type is ref cursor cursor; ; end Types;
page 67
R. Grin
Call Callab able leSt Stat atem ement ent cstm cstmt t = conn.prepareCall("{ ? = call list(?) }"); cstmt.setInt(2, 10); cstmt.registerOutParameter(1, OracleTypes.CURSOR); cstmt.execute(); Resul ResultS tSet et rs = ((OracleCallableStatement)cstmt) .getCursor(1); while whil e (rs (rs.ne .next( xt()) )) { System.out.println(rs.getString("nomE") + ";" + rs.getInt("dept")); }
create crea te or rep replac lace e functio func tion n listde listdept( pt(num num intege integer) r) return Types.curseur_type is empcursor empcur sor Types.curseur Types.curseur_type; _type; begin open empcurseur for select dept, nomE from emp wh e er r e dept = num; return empcurseur; end; JDBC
pa ge 68
Utiliser la fonction dans JDBC
Créer la fonction
R. Grin
JDBC
page 69
R. Grin
JDBC
pa ge 70
Fermer les ressources
Les resso ressources urces à fermer
Toutes les ressources JDBC doivent être fermées dès qu’elles ne sont plus utilisées Le plus souvent la fermeture doit se faire dans un bloc finally pour qu’elle ait lieu quel que soit le déroulement des opérations (avec ou sans erreurs) Les ressources sont automatiquement fermées par le ramasse-miettes mais il faut les fermer explicitement (on ne sait quand/si il va être lancé)
: leur fermeture est indispensable car c’est la ressource la plus coûteuse ; si on utilise un pool de connexions, la fermeture rend la connexion au pool Statement , et les sous-interfaces PreparedStatement et CallableStatement ResultSet : il est est automatiquement automatiquement fermé lorsque le statement qui l’a l’a engendr engendréé est fermé ou réexécuté, ou utilisé pour retrouver le prochain résultat (getMoreResults )
R. Grin
R. Grin
JDBC
page 71
Connection
JDBC
pa ge 72
12
Syntaxe spéciale de JDBC
Les Meta données
(« SQL Escape syntax »)
Comme avec les procédures stockées, JDBC a une syntaxe spéciale pour ne pas dépendre de particularités des différents SGBD : n n n
dat dates es : {d '2000-10-5'} appels de fonctions fonctions : {fn concat("Hot", concat("Hot", "Java")} "Java")} jointures externes : con.createStatement("SELECT * FROM" + " {oj {oj EMP RIG RIGHT HT OUTER OUTER JOIN DEPT" + " ON EMP.DEPT = DEPT.DEPT}");
n
JDBC permet de récupérer des informations sur le type de données que l'on vient de récupérer r écupérer par un SELECT (interface ResultSetMetaData),
mais aussiDatabaseMetaData) sur la base de données elle-même (interface Les données que l'on peut récupérer avec DatabaseMetaData dépendent du SGBD avec lequel on travaille
caractère caract ère d’échappeme d’échappement nt utilisé par LIKE :
WHERE Id LIKE '_%\\' {escape '\'} R. Grin
JDBC
page 73
R. Grin
JDBC
pa ge 74
DatabaseMetaData
ResultSetMetaData
private DatabaseMetaData metaData; private java.awt.List listTables = new List(10);
Re Resu sult ltSe Set t rs = stmt.executeQuery("SELECT * FROM emp");
. . .
Result Res ultSetM SetMetaD etaData ata rsmd rsmd = rs.getM rs.getMeta etaDat Data() a(); ;
for (int (int i = 1; i < <= = nbColonnes; nbColonnes; i++) i++) { String typeColonne typeColonne = rsmd.getColumnTy rsmd.getColumnTypeName( peName(i); i); String nomColonn nomColonne e = rsmd.getColumn rsmd.getColumnName(i Name(i); ); System.out.println("Colonne " + i + " de nom " + nomColo nomColonne nne + " de type type "
Resu Result ltSe Set t rs = metaData.getTables(null, null, "%", types); String nomTables; while whi le (rs (rs.ne .next() xt()) ) { nomTable nomTab le = rs.get rs.getString String(3); (3);
+ typeColonne);
listTables.add(nomTable);
}
Joker pour noms des tables et vues
} R. Grin
JDBC
page 75
R. Grin
JDBC
pa ge 76
Ordre Or dre SQ SQLL « dy dyna nami miqu ques es » Au moment où il écrit le programme, le programmeur peut ne pas connaître, le type SQL des valeurs insérées ou retrouvées dans la base de données Pour cela, JDBC a prévu les méthodes getObject() et setObject() qui effectuent des conversions automatiques (ou non) entre les types Java et SQL