Vous êtes sur la page 1sur 13

Présentation

‰ JDBC (Java Data Base Connectivity) permet l'accès


JDBC de base à 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
Université de Nice - Sophia Antipolis des SGBDs (quelques méthodes ne peuvent être
Richard Grin utilisées qu’avec certains SGBDs mais ne doivent
Version 3.1 – 16/8/07 être utilisées qu’en cas de nécessité impérieuse
pour améliorer les performances)

R. Grin JDBC page 2

Versions de SQL supportées Contenu de java.sql


‰ Les premières versions de JDBC supportent le
‰ Ce paquetage contient un grand nombre
standard SQL-2 Entry Level
d'interfaces et quelques classes
‰ JDBC 2 et 3 offrent en plus des fonctionnalités de
‰ Les interfaces constituent l’interface de
SQL3
programmation
‰ Pour des raisons d'efficacité un driver peut utiliser
‰ JDBC ne fournit pas les classes qui implantent
les possibilités particulières d'un SGBD (c'est permis
les interfaces
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
R. Grin JDBC page 3 R. Grin JDBC page 4

Drivers Types de drivers


‰ Pour travailler avec un SGBD il faut disposer de ‰ Type 1 : pont JDBC-ODBC
classes qui implantent les interfaces de JDBC ‰ Type 2 : driver qui fait appel à des fonctions
‰ Un ensemble de telles classes est désigné sous le natives non Java (le plus souvent en langage C)
nom de driver JDBC de l'API du SGBD que l'on veut utiliser
‰ Les drivers dépendent du SGBD auquel ils ‰ Type 3 : driver qui permet l'utilisation d'un serveur
permettent d'accéder middleware
‰ Tous les SGBD importants du marché ont un (et ‰ Type 4 : driver écrit entièrement en Java, qui
même plusieurs) driver JDBC, fourni par l'éditeur du utilise le protocole réseau du SGBD
SGBD ou par des éditeurs de logiciels indépendants

R. Grin JDBC page 5 R. Grin JDBC page 6

1
Type 1 : pont JDBC-ODBC Type 2 : utilise une API native
Application Java Application Java
Driver JDBC (en Java) Partie en Java (en Java) Driver
Les méthodes du driver (pas en Java)
Driver ODBC (pas en Java) Partie native
JDBC font appel à des
Les méthodes du driver JDBC fonctions d'une API du
font appel à des fonctions SGBD écrite dans un autre Protocole du SGBD
en langage C d'un driver ODBC langage que Java

SGBD SGBD

R. Grin JDBC page 7 R. Grin JDBC page 8

Type 3 : accès à un serveur middleware Type 4 : 100 % Java avec accès


direct au SGBD
Application Java Application Java
Les méthodes du driver JDBC
Driver en Java Driver en Java
se connectent par socket au
serveur middleware et lui Protocole du serveur
envoient les requêtes SQL ;
middleware Les méthodes du driver JDBC
le serveur middleware les Serveur middleware
utilisent des sockets pour Protocole du SGBD
traitent en se connectant au dialoguer avec le SGBD
SGBD selon son protocole réseau

SGBD SGBD
R. Grin JDBC page 9 R. Grin JDBC page 10

Types de drivers et applet untrusted Driver de type 3 et applet untrusted


‰ Une applet ne peut pas charger à distance du Le serveur middleware doit Code Java
code natif (non Java) ; elle ne peut donc pas être sur la même machine Applet
utiliser les drivers de type 1 et 2 que le serveur HTTP Driver en Java
‰ Pour des raisons de sécurité, une applet connexion par socket
untrusted (qui fonctionne dans le bac à sable ;
voir cours sur la sécurité) ne peut échanger des Serveur HTTP Serveur middleware
données par sockets qu'avec la machine d'où elle
provient, ce qui implique des contraintes avec les
drivers de type 3 et 4
SGBD
R. Grin JDBC page 11 R. Grin JDBC page 12

2
Driver de type 4 et applet untrusted
Code Java
Applet
Le serveur HTTP doit
Driver en Java
être sur la même machine
que le SGBD Travailler avec JDBC
connexion par socket

Serveur HTTP
SGBD

R. Grin JDBC page 13 R. Grin JDBC page 14

Pour utiliser JDBC Dans les classes qui utilisent JDBC


‰ A l’exécution, ajouter le chemin des classes du (des) ‰ Importer le paquetage java.sql (et java.math si
driver dans le classpath (option -classpath de la on utilise la classe BigDecimal) :
commande java) import java.sql.*;
‰ Par exemple, si Oracle est installé dans /oracle, le ‰ Charger en mémoire la classe du (des) driver (driver
driver peut être dans le fichier de type 4 fourni par Oracle pour cet exemple) avant
/oracle/jdbc/lib/ojdbc14.jar d'utiliser JDBC :
et l’application sera lancée par la commande Class.forName("oracle.jdbc.OracleDriver");
java –classpath /oracle/jdbc/lib/ojdbc14.jar:… ... Inutile avec JDBC 4 !

R. Grin JDBC page 15 R. Grin JDBC page 16

É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) Classes et interfaces de JDBC
3. Lancer l'exécution de ces instructions :
n interroger la base (executeQuery())
n ou modifier la base (executeUpdate())
n ou tout autre ordre SQL (execute())
4. Fermer la connexion (close())

R. Grin JDBC page 17 R. Grin JDBC page 18

3
Avertissement
‰ Nous étudierons tout d'abord les classes et ‰ Dans la suite du cours on utilise des raccourcis
méthodes de base de JDBC tels que « instance de Connection »
‰ Des nouvelles possibilités de JDBC 2 et 3, en ‰ Comme Connection est une interface, il faut
particulier celles qui sont liées à SQL3, seront traduire par « instance d’une classe qui
abordées dans les parties « JDBC avancé » et implémente Connection »
« JDBC et objet-relationnel »

R. Grin JDBC page 19 R. Grin JDBC page 20

Interfaces principales Classes principales


‰ Driver : renvoie une instance de Connection ‰ DriverManager : gère les drivers, lance les connexions
‰ Connection : connexion à une base aux bases
‰ Statement : ordre SQL ‰ Date : date SQL

‰ PreparedStatement : ordre SQL paramétré ‰ Time : heures, minutes, secondes SQL

‰ CallableStatement : procédure stockée sur le SGBD ‰ TimeStamp : date et heure, avec une précision à la

‰ ResultSet : lignes récupérées par un ordre SELECT


microseconde
‰ Types : constantes pour désigner les types SQL (pour
‰ ResultSetMetaData : description des lignes récupérées
par un SELECT les conversions avec les types Java)
‰ DatabaseMetaData : informations sur la base de
données
R. Grin JDBC page 21 R. Grin JDBC page 22

Exceptions Exceptions de JDBC 4 (1)


‰ SQLException : erreurs SQL ‰ SQLException a 3 sous-classes pour distinguer
différents types d’exception
‰ SQLWarning : avertissements SQL (classe fille de
n SQLNonTransientException : le problème
SQLException) ; le mécanisme de récupération des ne peut être résolu sans une action externe ;
avertissements est étudié plus loin inutile de réessayer la même action sans rien
‰ DataTruncation : avertit quand une valeur est tronquée faire de spécial
lors d'un transfert entre Java et le SGBD (classe fille de n SQLTransientException : le problème peut
SQLWarning) avoir été résolu si on attend un peu avant de
ressayer
n SQLRecoverableException : l’application
peut résoudre le problème en exécutant une
certaine action
R. Grin JDBC page 23 R. Grin JDBC page 24

4
Exceptions de JDBC 4 (2) Chaînage des exceptions
‰ Classes filles de SQLNonTransientException :
SQLDataException, ‰ Une requête SQL peut provoquer plusieurs
SQLFeatureNotSupportedException, exceptions
SQLIntegrityConstraintViolationException, ‰ On peut obtenir la prochaine exception par la
SQLInvalidAuthorizationException, méthode getNextException()
SQLNonTransientConnectionException, ‰ Une exception peut avoir une cause ; on l'obtient
SQLSyntaxErrorException par la méthode getCause()
‰ Classes filles de SQLTransientException : ‰ Toutes ces exceptions peuvent être parcourues
SQLTimeoutException, par une boucle « for-each » :
SQLTransactionRollbackException, catch(SQLException ex) {
SQLTransientConnectionException for (Throwable e : ex) { … }
R. Grin JDBC page 25 R. Grin JDBC page 26

Interface Driver URL d'une base de données


‰ Un URL pour une base de données est de la forme :
‰ La méthode connect() de Driver prend en jdbc:sous-protocole:base de donnée
paramètre un URL et renvoie une instance de
‰ Par exemple, pour Oracle :
l'interface Connection
jdbc:oracle:thin:@sirocco.unice.fr:1521:INFO
‰ Cette instance de Connection permettra de
n oracle:thin est le sous-protocole (driver « thin » ;
lancer des requêtes vers le SGBD
Oracle fournit aussi un autre type de driver)
‰ connect renvoie null si le driver ne convient
n @sirocco.unice.fr:1521:INFO désigne la base de
pas pour se connecter à la base désignée par
données INFO située sur la machine sirocco (le
l'URL
serveur du SGBD écoute sur le port 1521)
‰ Utilisée par DriverManager ; pas visible par ‰ La forme exacte des parties sous-protocole et base de
l’utilisateur de l’API données dépend du SGBD cible
R. Grin JDBC page 27 R. Grin JDBC page 28

Gestionnaire de drivers JDBC 4 et le driver


‰ La classe DriverManager gère les drivers (instances ‰ JDBC 4 utilise un autre mécanisme pour charger
de Driver) disponibles pour les différents SGBD le driver : il suffit d'indiquer le nom de la classe du
utilisés par le programme Java driver dans un fichier
‰ Pour qu'un driver soit utilisable, on doit charger sa META-INF/services/java.sql.Driver distribué avec
classe en mémoire : le driver JDBC
Class.forName("oracle.jdbc.OracleDriver"); ‰ Il est alors inutile d’appeler la méthode
‰ La classe crée alors une instance d'elle même et Class.forName
enregistre cette instance auprès de la classe
DriverManager

R. Grin JDBC page 29 R. Grin JDBC page 30

5
Obtenir une connexion Connexions et threads
‰ Pour obtenir une connexion à un SGBD, on demande ‰ Les connexions sont des ressources coûteuses,
cette connexion à la classe gestionnaire de drivers : et surtout longues à obtenir
static final String url =
"jdbc:oracle:thin:@sirocco.unice.fr:1521:INFO"; ‰ On peut donc être tenté de les réutiliser dans
Connection conn = plusieurs threads différents
DriverManager.getConnection(url,
‰ Mais, attention, les connexions ne peuvent être
"toto", "mdp");
partagées par plusieurs threads
‰ La classe DriverManager s'adresse à tour de rôle à
‰ À la place, utiliser les pools de connexions fournis
tous les drivers qui se sont enregistrés (méthode
avec les « sources de données » (étudiées dans
connect), jusqu'à ce qu'un driver lui fournisse une
une autre partie du cours)
connexion (ne renvoie pas null)
R. Grin JDBC page 31 R. Grin JDBC page 32

Transactions Niveau d’isolation


‰ Par défaut la connexion est en « auto-commit » : ‰ Le niveau d’isolation d’une transaction peut être
un commit est automatiquement lancé après modifié :
chaque ordre SQL qui modifie la base conn.setTransactionIsolation(
Connection.TRANSACTION_SERIALIZABLE);
‰ Le plus souvent il faut enlever l'auto-commit :
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 page 34

Instruction SQL simple Exécution de l’instruction SQL simple


‰ Instance de l'interface Statement ‰ La méthode à appeler dépend de la nature de
‰ La création est effectuée par la méthode l'ordre SQL que l’on veut exécuter :
createStatement() de Connection : n consultation (select) : executeQuery() renvoie un
Statement stmt = connexion.createStatement(); ResultSet pour récupérer les lignes une à une
n modification des données (update, insert, delete)
ou ordres DDL (create table,…) : executeUpdate()
renvoie le nombre de lignes modifiées
n si on ne connaît pas à l'exécution la nature de
l'ordre SQL à exécuter ou si l'ordre peut renvoyer
plusieurs résultats : execute()
R. Grin JDBC page 35 R. Grin JDBC page 36

6
Consultation des données (SELECT) Interface ResultSet
‰ executeQuery() renvoie une instance de
Statement stmt = conn.createStatement(); ResultSet
// rset contient les lignes renvoyées ‰ ResultSet va permettre de parcourir toutes les
ResultSet rset = lignes renvoyées par le select
stmt.executeQuery("SELECT nomE FROM emp");
‰ Au début, ResultSet est positionné avant la
// On récupère chaque ligne une à une
première ligne et il faut donc commencer par le
while (rset.next())
faire avancer à la première ligne en appelant la
System.out.println (rset.getString(1));
méthode next()
// ou . . . (rset.getString("nomE"));
stmt.close(); La première colonne a le numéro 1
‰ Cette méthode permet de passer à la ligne
suivante ; elle renvoie true si cette ligne
Voir plus loin le transparent sur la suivante existe et false sinon
R.fermeture
Grin des ressources JDBC page 37 R. Grin JDBC page 38

Interface ResultSet ResultSet - performances


‰ Quand ResultSet est positionné sur une ligne
‰ Quand le réseau est lent et que l’on veut
les méthodes getXXX permettent de récupérer
récupérer de nombreuses lignes, il est parfois
les valeurs des colonnes de la ligne :
possible d’améliorer sensiblement les
n getXXX(int numéroColonne) performances en modifiant le nombre de lignes
n getXXX(String nomColonne) (nom simple d’une récupérées à chaque fois par le ResultSet (il faut
colonne, pas préfixé par un nom de table ; dans le cas effectuer des tests pour chaque cas)
d’une jointure utiliser un alias de colonne)
‰ Pour cela, on utilise la méthode setFetchSize
‰ XXX désigne le type Java de la valeur que l'on va de Statement
récupérer, par exemple String, Int ou Double
‰ C’est seulement une indication qu’on donne au
‰ Par exemple, getInt renvoie un int
driver ; il n’est pas obligé d’en tenir compte
R. Grin JDBC page 39 R. Grin JDBC page 40

Types JDBC/SQL 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 ‰ CHAR, VARCHAR, LONGVARCHAR
différences importantes ‰ BINARY, VARBINARY, LONGVARBINARY
‰ Pour cacher ces différences, JDBC définit ses ‰ BIT, TINYINT, SMALLINT, INTEGER, BIGINT
propres types SQL dans la classe Types, sous forme ‰ REAL, DOUBLE, FLOAT
de constantes nommées
‰ DECIMAL, NUMERIC
‰ Ils sont utilisés par les programmeurs quand ils
‰ DATE, TIME, TIMESTAMP
doivent préciser un type SQL (setNull,
setObject, registerOutParameter) ‰ BLOB, CLOB
‰ ARRAY, DISTINCT, STRUCT, REF Types SQL3
‰ Le driver JDBC fait la traduction de ces types dans
‰ JAVA_OBJECT
les types du SGBD
R. Grin JDBC page 41 R. Grin JDBC page 42

7
Correspondances Correspondances avec getXXX()
entre types Java et SQL ‰ On a une grande latitude ; ainsi, presque tous les types
SQL peuvent être retrouvés par getString()
‰ Il reste le problème de la correspondance entre les
‰ Cependant, des méthodes sont recommandées ; voici
types Java et les types SQL des exemples :
‰ Dans un programme JDBC, les méthodes getXXX, n CHAR et VARCHAR : getString, LONGVARCHAR :
setXXX servent à préciser cette correspondance getAsciiStream et getCharacterStream
‰ Par exemple, getString indique que l’on veut n BINARY et VARBINARY : getBytes, LONGVARBINARY :
getBinaryStream
récupérer la donnée SQL dans une String n REAL : getFloat, DOUBLE et FLOAT : getDouble
‰ C'est le rôle du driver particulier à chaque SGBD de n DECIMAL et NUMERIC : getBigDecimal
faire les traductions correspondantes ; une exception n DATE : getDate, TIME : getTime, TIMESTAMP :
peut être lancée si ça n’est pas possible getTimestamp

R. Grin JDBC page 43 R. Grin JDBC page 44

Types Date en Java et en SQL Exemple


‰ java.sql contient une classe Date qui est utilisé
par JDBC pour les échanges de dates entre Java ‰ Pour passer de java.util.Date à
et la base de données java.sql.Date, utiliser la méthode getTime():
‰ Cette classe hérite de la classe java.util.Date ‰ java.util.Date date = new java.util.Date();
java.sql.Date dateSQL =
‰ Elle correspond à un temps en millisecondes
new java.sql.Date(date.getTime());
‰ Normalement les dates SQL ne contiennent pas java.sql.Time time =
d’indication sur l’heure dans la journée ; il faut new Time(date.getTime());
utiliser les types SQL TIME et TIMESTAMP pour java.sql.Timestamp time =
l’heure dans la journée new Timestamp(date.getTime());
‰ Pour passer de java.util.Date à
java.sql.Date, utiliser la méthode getTime()
R. Grin JDBC page 45 R. Grin JDBC page 46

Valeur NULL
Manipulation des dates
Statement stmt = conn.createStatement();
ResultSet rset = stmt.executeQuery(
‰ Un petit rappel sur les dates en Java :
"SELECT nomE, comm FROM emp");
n mise en forme avec la classe
while (rset.next()) {
java.text.DateFormat nom = rset.getString("nomE");
n calculs sur les dates avec la classe commission = rset.getDouble("comm");
java.util.Calendar if (rset.wasNull())
‰ Voir le cours sur les dates dans le support System.out.println(nom + ": pas de comm");
else
« Compléments divers »
System.out.println(nom + " a " + commission
+ " € de commission");
}

R. Grin JDBC page 47 R. Grin JDBC page 48

8
Modification des données (INSERT, Instruction SQL paramétrée
UPDATE, DELETE)
‰ La plupart des SGBD (dont Oracle) peuvent
Statement stmt = conn.createStatement(); n'analyser qu'une seule fois une requête
String ville = "NICE"; exécutée un grand nombre de fois durant une
int nbLignesModifiees = stmt.executeUpdate( connexion
"INSERT INTO dept (dept, nomD, lieu) " ‰ JDBC permet de profiter de ce type de
+ "VALUES (70, 'DIRECTION'," fonctionnalité par l'utilisation de requêtes
+ "'" + ville + "')"); paramétrées ou de procédures stockées
N'oubliez pas
stmt.close(); l'espace ! ‰ Les requêtes paramétrées sont associées aux
instances de l'interface PreparedStatement qui
hérite de l'interface Statement
R. Grin JDBC page 49 R. Grin JDBC page 50

Création d'une requête paramétrée Requête paramétrée –


Valeurs des paramètres
PreparedStatement pstmt =
conn.prepareStatement("UPDATE emp SET sal = ?" ‰ Les valeurs des paramètres sont données par les
+ " WHERE nome = ?"); méthodes setXXX(n, valeur)
‰ On choisit la méthode setXXX suivant le type
‰ Les "?" indiquent les emplacements des paramètres Java de la valeur que l'on veut mettre dans la
‰ Cette requête pourra être exécutées avec plusieurs base de données
couples de valeurs : (2500, ‘DUPOND’), (3000, ‰ C'est au programmeur de passer une valeur Java
‘DURAND’), etc. du bon type à la méthode setXXX
‰ Le driver JDBC fait la conversion dans le bon
format pour le SGBD
R. Grin JDBC page 51 R. Grin JDBC page 52

Requête paramétrée - Exemple Requête paramétrée - NULL


PreparedStatement pstmt = ‰ Pour passer la valeur NULL à la base de donnée,
conn.prepareStatement( on peut
"UPDATE emp SET sal = ? "
n utiliser la méthode setNull(n, type) (type de la
+ "WHERE nomE = ?"); commence à 1
classe Types)
for (int i=0; i<10; i++) { et pas à 0
n ou passer la valeur Java null si la méthode
pstmt.setDouble(1,employe[i].getSalaire());
setXXX() attend un objet en paramètre
pstmt.setString(2, employe[i].getNom());
pstmt.executeUpdate();
}

R. Grin JDBC page 53 R. Grin JDBC page 54

9
Avantages des PreparedStatement Procédures stockées
‰ Leur traitement est plus rapide s’ils sont utilisés
plusieurs fois avec plusieurs paramètres ‰ Les procédures stockées permettent non
‰ Ils améliorent aussi la portabilité car les méthodes seulement de précompiler des ordres SQL mais
setXXX gèrent les différences entre SGBD aussi de les regrouper
‰ En effet, les SGBD n’utilisent pas tous les mêmes ‰ Comme les accès réseau aux bases de données
formats de date ('JJ/MM/AA' ou 'AAAA-MM-JJ' ralentissent les applications, les procédures
par exemple) ou de chaînes de caractères (pour stockées permettent souvent d’améliorer les
les caractères d’« échappement ») performances
‰ Mais on peut aussi utiliser pour cela la syntaxe ‰ Mais elles nuisent aussi souvent à la portabilité

(un peu lourde) « SQL Escape » (voir plus loin) des applications
‰ Ils évitent l'injection de code SQL
R. Grin JDBC page 55 R. Grin JDBC page 56

Exemple de procédure stockée (Oracle) Création d'une procédure stockée


create or replace procedure augmenter
(unDept in integer, pourcentage in number, ‰ Les procédures stockées sont associées aux
cout out number) is instances de l'interface CallableStatement qui hérite
begin de l'interface PreparedStatement
select sum(sal) * pourcentage / 100 ‰ La création d'une instance de CallableStatement se
into cout fait par l'appel de la méthode prepareCall de la
from emp classe Connection
where dept = unDept;
‰ On passe à cette méthode une chaîne de caractères
update emp
set sal = sal * (1 + pourcentage / 100) qui décrit comment sera appelée la procédure
where dept = unDept; stockée, et si la procédure renvoie une valeur ou
end; non
R. Grin JDBC page 57 R. Grin JDBC page 58

Syntaxe pour les procédures stockées Exemple


‰ La syntaxe de l'appel des procédures stockées n'est CallableStatement cstmt =
pas standardisée ; elle diffère suivant les SGBD conn.prepareCall("{? = call augmenter(?,?)}");
‰ JDBC utilise sa propre syntaxe pour pallier ce
problème :
n si la procédure renvoie une valeur :
Le driver
{ ? = call nom-procédure(?, ?,...) } traduira
n si elle ne renvoie aucune valeur : dans la
{ call nom-procédure(?, ?,...) } syntaxe
n si on ne lui passe aucun paramètre : du SGBD
{ call nom-procédure }
R. Grin JDBC page 59 R. Grin JDBC page 60

10
Lancement d'une procédure stockée Utilisation d'une procédure stockée
‰ L'appel de la procédure est précédé du passage à la CallableStatement csmt = conn.prepareCall(
procédure des paramètres « in » et « in/out » par les "{ call augmenter(?, ?, ?) }");
// 2 chiffres après la virgule pour 3ème paramètre
méthodes setXXX() (idem requêtes paramétrées)
csmt.registerOutParameter(3, Types.DECIMAL, 2);
‰ On doit indiquer le type des paramètres « out » et // Augmentation de 2,5 % des salaires du dept 10
« in/out » par la méthode registerOutParameter() csmt.setInt(1, 10);
‰ Ensuite on lance la procédure par une des méthodes csmt.setDouble(2, 2.5);
executeQuery(), executeUpdate() ou execute(), suivant csmt.executeQuery(); // ou execute()
le type des commandes SQL que la procédure contient double cout = csmt.getDouble(3);
‰ On récupère les paramètres « out » et « in/out » par les System.out.println("Cout total augmentation : "
méthodes getXXX() (idem requêtes paramétrées) + cout);

R. Grin JDBC page 61 R. Grin JDBC page 62

Procédures stockées contenant Ordre SQL quelconque


plusieurs ordres SQL ‰ On peut ne pas savoir quels ordres SQL sont
‰ Une procédure stockée peut contenir plusieurs contenus dans une procédure stockée
ordres SQL de divers types ‰ Dans ce cas, on utilise le fait que
‰ Pour retrouver tous les résultats de ces ordres n execute renvoie true si le 1er résultat est un ResultSet
(ResultSet ou nombre de lignes modifiées), on n getMoreResults renvoie true si le résultat suivant est
utilise la méthode getMoreResults() de la classe un ResultSet
Statement n getUpdateCount() : renvoie le nombre de lignes
modifiées, ou -1 s'il n'y a plus de résultat (ou si le
‰ Ainsi, si elle contient 2 ordres SELECT, on récupère résultat est un ResultSet)
le 1er ResultSet par getResultSet ; on passe à la
2ème requête par getMoreResults et on récupère ‰ On peut exécuter tous les ordres dans une boucle
son ResultSet par getResultSet dont la condition de fin est
!getMoreResults() && getUpdateCount() == -1
R. Grin JDBC page 63 R. Grin JDBC page 64

Schéma de code Renvoyer un ResultSet


d’une procédure stockée avec Oracle
boolean retval = cstmt.execute();
do {
if (retval == false) { // pas un ResultSet
int count = cstmt.getUpdateCount(); ‰ Attention, les 4 transparents qui suivent sur ce
if (count == -1) break; // c’est fini !
else { // traite l’ordre SQL
sujet sont particuliers à Oracle ; consultez le
. . . manuel de votre SGBD si vous travaillez avec un
} autre SGBD
}
‰ Il faut utiliser le type « ref cursor » d’Oracle et des
else { // ResultSet
ResultSet rs = cstmt.getResultSet(); extensions JDBC fournies avec le driver distribué
. . . // traite le ResultSet par Oracle
}
retval = cstmt.getMoreResults(); ‰ Le curseur Oracle sera fermé quand l’instance de
while (true); CallableStatement sera fermée
R. Grin JDBC page 65 R. Grin JDBC page 66

11
Fonction qui renvoie un curseur Créer le type référence de curseur
‰ Il faut ‰ Créer un nom de type pour la référence de curseur
1. Créer un type pour la référence de curseur qu’on va renvoyer
qu’on va renvoyer ‰ Pour utiliser ensuite le type, il faut le créer dans un
2. Créer la fonction qui renvoie la référence de paquetage :
create or replace package Types AS
curseur
type curseur_type is ref cursor;
end Types;

R. Grin JDBC page 67 R. Grin JDBC page 68

Créer la fonction Utiliser la fonction dans JDBC


create or replace CallableStatement cstmt =
function listdept(num integer) conn.prepareCall("{ ? = call list(?) }");
cstmt.setInt(2, 10);
return Types.curseur_type
cstmt.registerOutParameter(1,
is OracleTypes.CURSOR);
empcursor Types.curseur_type; cstmt.execute();
begin ResultSet rs =
open empcurseur ((OracleCallableStatement)cstmt)
for select dept, nomE .getCursor(1);
from emp where dept = num; while (rs.next()) {
return empcurseur; System.out.println(rs.getString("nomE")
end; + ";" + rs.getInt("dept"));
}
R. Grin JDBC page 69 R. Grin JDBC page 70

Fermer les ressources Les ressources à fermer


‰ Toutes les ressources JDBC doivent être fermées ‰ Connection : leur fermeture est indispensable car
dès qu’elles ne sont plus utilisées c’est la ressource la plus coûteuse ; si on utilise un
‰ Le plus souvent la fermeture doit se faire dans un pool de connexions, la fermeture rend la connexion
bloc finally pour qu’elle ait lieu quel que soit le au pool
déroulement des opérations (avec ou sans ‰ Statement, et les sous-interfaces
erreurs) PreparedStatement et CallableStatement
‰ Les ressources sont automatiquement fermées par ‰ ResultSet : il est automatiquement fermé lorsque
le ramasse-miettes mais il faut les fermer le statement qui l’a engendré est fermé ou
explicitement (on ne sait quand/si il va être lancé) réexécuté, ou utilisé pour retrouver le prochain
résultat (getMoreResults)
R. Grin JDBC page 71 R. Grin JDBC page 72

12
Syntaxe spéciale de JDBC
Les Meta données
(« SQL Escape syntax »)
‰ Comme avec les procédures stockées, JDBC a une ‰ JDBC permet de récupérer des informations sur
syntaxe spéciale pour ne pas dépendre de le type de données que l'on vient de récupérer
particularités des différents SGBD : par un SELECT (interface ResultSetMetaData),
n dates : {d '2000-10-5'} ‰ mais aussi sur la base de données elle-même
n appels de fonctions : {fn concat("Hot", "Java")} (interface DatabaseMetaData)
n jointures externes : ‰ Les données que l'on peut récupérer avec
con.createStatement("SELECT * FROM"
+ " {oj EMP RIGHT OUTER JOIN DEPT" DatabaseMetaData dépendent du SGBD avec
+ " ON EMP.DEPT = DEPT.DEPT}"); lequel on travaille
n caractère d’échappement utilisé par LIKE :
WHERE Id LIKE '_%\\' {escape '\'}
R. Grin JDBC page 73 R. Grin JDBC page 74

ResultSetMetaData DatabaseMetaData
private DatabaseMetaData metaData;
ResultSet rs =
private java.awt.List listTables = new List(10);
stmt.executeQuery("SELECT * FROM emp");
. . .
ResultSetMetaData rsmd = rs.getMetaData();
metaData = conn.getMetaData();
int nbColonnes = rsmd.getColumnCount();
String[] types = { "TABLE", "VIEW" };
for (int i = 1; i <= nbColonnes; i++) {
ResultSet rs =
String typeColonne = rsmd.getColumnTypeName(i);
metaData.getTables(null, null, "%", types);
String nomColonne = rsmd.getColumnName(i);
String nomTables;
System.out.println("Colonne " + i + " de nom "
while (rs.next()) { Joker pour
+ nomColonne + " de type " noms des
nomTable = rs.getString(3);
+ typeColonne); tables et vues
listTables.add(nomTable);
}
}
R. Grin JDBC page 75 R. Grin JDBC page 76

Ordre SQL « dynamiques »


‰ 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

R. Grin JDBC page 77

13

Vous aimerez peut-être aussi