Vous êtes sur la page 1sur 17

Polytech'Marseille, Dpartement "Informatique", 4me anne

Bases de donnes

T.P.
Interaction JAVA - Bases de donnes
Introduction JDBC

Ce TP1 a pour but de vous initier JDBC la faon d'un tutoriel. Si vous souhaitez des complments, vous
pouvez consulter les documents suivants :
- Support de cours : http://nicolas.durand.perso.luminy.univmed.fr/pub/bd/tpjdbc/JDBC.pdf
- Site officiel de SUN : http://java.sun.com/javase/technologies/database/
L'API2 JDBC (Java DataBase Connectivity) permet aux applications JAVA de communiquer avec les
gestionnaires de bases de donnes dans un langage universel l'instar des pilotes ODBC (Open DataBase
Connectivity) dans le monde Windows. Les applications sont ainsi indpendantes de la base de donnes
utilise. L'utilisation d'un pilote JDBC rend possible trois points :
- Etablir une connexion avec une base de donnes,
- Envoyer des requtes SQL,
- Traiter les rsultats.
Nous utiliserons le SGBD ORACLE de l'cole.

Un exemple de programme utilisant JDBC se trouve en annexe. Ne vous inquitez pas si vous ne
comprenez pas le code de cet exemple ! Nous allons reprendre chaque tape dans le TP.
Lisez attentivement chaque partie et lancez-vous dans la programmation seulement pour les 6 exercices.

1) Prliminaire
Rcuprez le driver JDBC pour ORACLE l'adresse suivante :
http://nicolas.durand.perso.luminy.univmed.fr/pub/bd/tpjdbc/ojdbc14.jar

Implantation d'une petite base de donnes pour ce TP.


Supposez que notre exemple de base de donnes est utilis par le propritaire d'un petit bar appel "The
Coffee Break", o les grains de caf sont vendus la livre et que le caf torrfi est vendu la tasse. Pour
faire simple, nous imaginons que le propritaire a besoin de deux tables, une pour le type de caf et une
autre pour ses fournisseurs.
Tout d'abord, nous vous montrons comment ouvrir une connexion avec votre SGBD. Nous vous montrons
avec quelle facilit d'utilisation JDBC passe ces instructions SQL votre SGBD et comment il les retourne.

2) tablir une connexion


La premire chose que vous devez faire est d'tablir une connexion avec votre SGBD la base de donnes
concerne.
Cela implique deux tapes :
- Charger les pilotes,
- Crer la connexion.
1
1
2

Inspirer du tutoriel JDBC/MySQL : http://www-sop.inria.fr/members/Patrick.Itey/cours/jdbc/cnrs/tps/1.html


Application Programming Interface

Polytech'Marseille, Dpartement "Informatique", 4me anne


Bases de donnes

Avec le driver JDBC pour ORACLE, le nom de la classe qui l'implmente est "oracle.jdbc.OracleDriver"
Ainsi, vous devez charger le pilote avec cette ligne de code :
Class.forName("oracle.jdbc.OracleDriver");

Vous n'avez pas besoin de crer une instance du pilote et de le rfrencer avec DriverManager. Il suffit
d'appeler Class.forName qui le fera pour vous automatiquement. Si vous aviez crer votre propre
instance, vous creriez un duplicata inutile.
Une fois le pilote charg, vous tes prt pour crer une connexion avec un SGDB.

3) Crer une connexion


La deuxime tape pour tablir une connexion est d'avoir le pilote appropri pour se connecter votre
SGBD. Cette ligne de code illustre l'ide :
Connection conn = DriverManager.getConnection(url,"MonLogin","MonMotDePasse");

Cette tape est aussi trs simple. Le plus dur est de fournir la bonne URL.
Si vous utilisez un pilote JDBC dvelopp par un tiers, la documentation vous dira quel sous-protocole
utiliser, donc, que mettre aprs "jdbc:" dans l'URL JDBC.
Voici les paramtres connaitre pour formater cette URL de connexion JDBC :
le nom de la machine o s'excute le SGBD : pedaserv1.luminy.univmed.fr
le numro de port sur lequel le SGBD est l'coute : 1521
s'il y a un nom de base de donnes renseigner (ce n'est pas ntre cas) : test
le login : compten
le mot de passe : compten (ou celui qui vous avez choisi).
Ainsi :
String url = "jdbc:oracle:thin:@pedaserv1.luminy.univmed.fr:1521";
Connection conn = DriverManager.getConnection(url,"compten","compten");

S'il y a un nom de base de donnes renseigner, l'URL devient :


String url = "jdbc:oracle:thin:@pedaserv1.luminy.univmed.fr:1521:test";

Si un des pilotes que vous avez charg reconnat l'URL JDBC fournit dans la mthode
DriverManager.getConnection, ce pilote tablira une connexion avec le SGBD spcifi dans l'URL
JDBC. La classe DriverManager prend en charge tous les dtails afin d'tablir, pour vous, la connexion.
Si vous avez crit votre propre pilote, vous n'aurez probablement jamais utiliser des mthodes de
l'interface Driver, et la seule mthode dont vous aurez besoin est DriverManager.getConnection.
La connexion retourne par la mthode DriverManager.getConnection est une connexion ouverte, ce
qui vous permet de passer vos instructions SQL vers votre SGBD. Dans l'exemple prcdant, conn est une
connexion ouverte, et nous l'utilisons pour les exemples du TP.

Remarque importante : il faut librer les ressources. Une connexion doit tre ferme si elle n'est plus
utilise ( faire systmatiquement en fin de programme).
conn.close();

Polytech'Marseille, Dpartement "Informatique", 4me anne


Bases de donnes

4) Crer et alimenter les tables


Tout d'abord, nous allons crer les tables pour notre exemple de base de donnes. La table CAFES, contient
les informations essentielles concernant les cafs vendus par "The Coffee Break", incluant le nom du caf,
son prix, le nombre de livres vendues dans la semaine courante, et le nombre de livres vendues jusqu'
maintenant. La table CAFES, que nous dcrirons plus en dtails plus tard, est la suivante :
NOM_CAFE
Colombian
French_Roast
Espresso
Colombian_Decaf
French_Roast_Decaf

FO_ID
101
49
150
101
49

PRIX
7.99
8.99
9.99
8.99
9.99

VENTES
0
0
0
0
0

TOTAL
0
0
0
0
0

La colonne qui contient le nom du caf est NOM_CAFE, elle supporte des valeurs de type VARCHAR et a
un maximum de 32 caractres de long. Comme nous utiliserons un nom diffrent pour chaque type de caf
vendu, le nom identifiera un caf de faon unique, et pourra donc servir de cl primaire notre table. La
seconde colonne, FO_ID, contient un nombre qui identifie le fournisseur de caf, cette variable SQL est de
type INTEGER. La troisime colonne, appele PRIX, est de type FLOAT. La colonne appele VENTES
contient des valeurs de type INTEGER, et indique le nombre de livres de caf vendues durant la semaine.
La dernire colonne, TOTAL, contient un INTEGER qui donne le nombre de livres de caf vendues jusqu'
maintenant.
FOURNISSEURS, la seconde table, donne des informations pour chaque fournisseur :
FO_ID NOM_FO
101
Acme, Inc
49
Superior Coffee
The
High
150
Ground

RUE
99 Market Street
1 Party Place

VILLE
GroundVille
Mendocino

ETAT CODE_POSTAL
CA
95199
CA
95460

100 Coffee Lane

Meadows

CA

93966

La colonne FO_ID est la cl primaire dans la table FOURNISSEURS, elle identifie de faon unique chacun
des fournisseurs de caf. Notez que dans la table CAFES, FO_ID est une cl trangre qui rfrence
FO_ID de la table FOURNISSEURS.
L'instruction SQL qui suit, cre la table CAFES.
CREATE TABLE CAFES (
NOM_CAFE VARCHAR(32),
FO_ID INTEGER,
PRIX FLOAT,
VENTES INTEGER,
TOTAL INTEGER
)

Ce code ne se termine pas par une fin d'instruction. Le pilote que vous utilisez apportera automatiquement
le symbole qui mettra fin l'instruction.

Polytech'Marseille, Dpartement "Informatique", 4me anne


Bases de donnes

Maintenant, mettons le code entre guillemet (pour en faire une chane de caractres) et assignons ce
String une variable creerTableCafes que nous utiliserons plus tard dans notre code JDBC.
Remarque : un String qui s'tend sur plus d'une ligne peut poser des problmes. Par consquent, coupez
en plusieurs lignes et concatnez les avec un "+".
String creerTableCafes = "CREATE TABLE CAFES ("
+ " NOM_CAFE VARCHAR(32), FO_ID INTEGER, PRIX FLOAT,"
+ " VENTES INTEGER, TOTAL INTEGER)";

Le type de donnes que nous avons utilis dans notre CREATE TABLE est le type SQL (aussi appel type
JDBC) gnrique qui est dfini dans java.sql.Types. Les SGBD utilisent gnralement ces types standards.
Avant de vous lancer dans votre premier programme JDBC, nous allons traverser les notions de base.
4.1 Crer une instruction JDBC
Un objet Statement est ce que votre instruction SQL envoie vers le SGBD. Vous crerez simplement un
objet Statement puis, l'excuterez, lui fournissant la mthode d'excution approprie avec l'instruction
SQL que vous voulez envoyer. Pour une instruction SELECT, la mthode utiliser est executeQuery.
Pour les instructions visant crer ou modifier des tables, la mthode est executeUpdate.
Vous devez avoir l'instance d'une connexion active pour crer un objet Statement. Dans l'exemple
suivant, nous utilisons notre objet Connection conn, pour crer l'objet Statement stmt :
Statement stmt = conn.createStatement();

A ce niveau, stmt existe, mais il n'a aucune instruction SQL passer au SGBD. Nous devrons la fournir
dans la mthode que nous utiliserons pour excuter stmt. Par exemple, dans le code suivant, nous
proposons executeUpdate avec l'instruction SQL :
stmt.executeUpdate(creerTableCafes);

Remarque importante : un statement doit tre ferme s'il n'est plus utilis.
stmt.close();

4.2 Excuter une instruction


Nous avons utilis la mthode executeUpdate car l'instruction SQL contenue dans creerTableCafes
est une DDL (Data Definition Language). Les instructions consistant crer, modifier ou effacer des tables
sont des exemples d'instructions DDL et sont excutes avec la mthode executeUpdate. La mthode
executeUpdate est utilise pour excuter les instructions SQL qui mettent jour une table. En pratique,
executeUpdate est utilise le plus souvent pour mettre des tables jour plutt que pour les crer, car une
table ne peut tre cre qu'une seule fois, mais mise jour plusieurs fois.
4.3 L'entre de donnes dans une table
Nous vous avons montr comment crer la table CAFES en spcifiant le nom des colonnes et le type de
donnes qu'elles contiennent, mais cela ne fait que construire la structure de la table. Elle ne contient
aucune donne. Nous allons entrer nos donnes dans une table une ligne la fois, fournissant l'information
stocker dans chacune des colonnes de cette ligne. Notez que les valeurs insres dans les colonnes
doivent tre dans le mme ordre que les colonnes leur cration.
4

Polytech'Marseille, Dpartement "Informatique", 4me anne


Bases de donnes

Le code suivant insre une ligne de donnes, Colombian dans la colonne NOM_CAFE, 101 dans FO_ID,
7.99 dans PRIX, 0 dans VENTES et 0 dans TOTAL. ("The Coffee Break" vient juste de commencer, c'est
pourquoi certaines valeurs sont misent 0). Comme nous l'avons fait pour crer des tables, nous allons
dclarer un objet Statement, et l'excuter en utilisant la mthode executeUpdate.
Statement stmt = conn.createStatement();
stmt.executeUpdate("INSERT INTO CAFES VALUES ('Colombian', 101, 7.99, 0, 0)");

Le code qui suit insre une deuxime ligne dans la table CAFES. Nous rutilisons l'objet Statement
stmt plutt que d'en crer un nouveau pour chaque excution.
stmt.executeUpdate("INSERT INTO CAFES"
+ " VALUES ('French_Roast', 49, 8.99, 0, 0)");

Les valeurs pour les lignes restantes peuvent tre insres comme il suit :
stmt.executeUpdate("INSERT
+ " VALUES
stmt.executeUpdate("INSERT
+ " VALUES
stmt.executeUpdate("INSERT
+ " VALUES

INTO CAFES"
('Espresso', 150, 9.99, 0, 0)");
INTO CAFES"
('Colombian_Decaf', 101, 8.99, 0, 0)");
INTO CAFES"
('French_Roast_Decaf', 49, 9.99, 0, 0)");

Exercice 1
Ecrivez un programme JAVA permettant de se connecter votre base de donnes ORACLE, de crer la
table CAFES et d'alimenter cette dernire.
N'oubliez pas de fermer les ressources la fin de votre programme.

4.4 Accder aux donnes d'une table


Maintenant que la table CAFES contient des valeurs, nous pouvons crire une instruction SELECT pour
avoir accs ces valeurs.
SELECT * FROM CAFES;
Le rsultat, dsignant la table entire, devrait ressembler ceci :
NOM_CAFE
Colombian
French_Roast
Espresso
Colombian_Decaf
French_Roast_Decaf

FO_ID
101
49
150
101
49

PRIX
7.99
8.99
9.99
8.99
9.99

VENTES
0
0
0
0
0

TOTAL
0
0
0
0
0

Le rsultat ci-dessus est ce que vous devez voir sur votre terminal si vous avez entr la requte SQL
directement dans le systme de la base de donnes. Lorsque nous accderons une base de donnes au
travers d'une application JAVA, nous aurons besoin de prendre les rsultats, pour que nous puissions les
utiliser. Nous dcrivons comment faire dans la prochaine section.
5

Polytech'Marseille, Dpartement "Informatique", 4me anne


Bases de donnes

5) Accder aux valeurs d'un ResultSet


Nous allons maintenant voir comment envoyer les requtes crites dans la section prcdente depuis un
programme crit en JAVA, et comment accder ce rsultat.
JDBC renvoie les rsultats dans un objet ResultSet. Nous avons donc besoin de dclarer une instance de
la classe ResultSet pour contenir nos rsultats. Le code qui suit dclare l'objet ResultSet rs et lui
assigne le rsultat de notre requte prcdente :
ResultSet rs = stmt.executeQuery("SELECT NOM_CAFE, PRIX FROM CAFES");

5.1 Utiliser la mthode next


La variable rs, qui est une instance de ResultSet, contient les lignes de cafs et leurs prix. Pour pouvoir
accder leurs noms et leurs prix, nous irons dans chaque ligne et rcuprerons les valeurs selon leur
type. La mthode next dplace ce qui est appel "curseur" la ligne suivante, et fait de cette ligne
(appele la ligne courante) celle sur laquelle nous travaillons. Initialement, ce curseur est positionn juste
au dessus de la premire ligne d'un objet ResultSet, donc le premier appel la mthode next dplace le
curseur la premire ligne et en fait la ligne courante. L'invocation successive de la mthode next dplace
le curseur vers le bas, ligne par ligne.
5.2 Utiliser la mthode getXXX
Nous utilisons la mthode getXXX du type appropri pour accder une valeur dans chaque colonne. Par
exemple, la premire colonne de chaque ligne du resultset est NOM_CAFE, qui contient une valeur de type
VARCHAR. La mthode pour accder une valeur de type VARCHAR est getString. La seconde
colonne de chaque ligne contient une valeur de type FLOAT, et la mthode pour accder ces valeurs est
getFloat.
Le code qui suit, accde aux valeurs contenues dans la ligne courante du resultset et affiche la ligne avec le
nom suivit d'une tabulation puis le prix. chaque fois que la mthode next est invoque, la ligne suivante
devient la ligne courante, et la boucle continue jusqu' ce qu'il n'y ait plus de ligne dans le resultset.
String requete = "SELECT NOM_CAFE, PRIX FROM CAFES";
ResultSet rs = stmt.executeQuery(requete);
while(rs.next()) {
String nom = rs.getString("NOM_CAFE");
float prix = rs.getFloat("PRIX");
System.out.println(nom + "\t" + prix);
}

Ce programme affiche ceci :


Colombian 7.99
French_Roast
8.99
Espresso
9.99
Colombian_Decaf 8.99
French_Roast_Decaf
9.99

Voyons maintenant plus prcisment comment la mthode getXXX fonctionne en examinant les deux
instructions getXXX dans ce code. Premirement, examinons getString.
String nom = rs.getString("NOM_CAFE");
6

Polytech'Marseille, Dpartement "Informatique", 4me anne


Bases de donnes

La mthode getString est invoque sur l'objet ResultSet rs, donc getString doit accder aux
valeurs contenues dans la colonne NOM_CAFE de la ligne courante de rs. La valeur que getString
rapporte a t convertie du SQL VARCHAR, au String de JAVA, et a t assigne l'objet String
nom. La situation est la mme avec la mthode getFloat, l'exception prs, qu'il rapporte la valeur
contenue dans la colonne PRIX, qui est un FLOAT SQL, et la convertir en float de JAVA avant de
l'assigner la variable prix.
JDBC offre deux faons d'identifier une colonne dont une mthode getXXX prendra la valeur. Une des
faons est de donner le nom de la colonne, comme dans l'exemple ci-dessus, et la seconde, est de donner
l'indice de la colonne (numro de la colonne), o 1 dsigne la premire colonne, 2 la deuxime colonne et
ainsi de suite. Utiliser le numro de la colonne la place de son nom donne le code suivant :
String nom = rs.getString(1);
float prix = rs.getFloat(2);

La premire ligne de code prend la valeur de la premire colonne de la ligne courante de rs (colonne
NOM_CAFE), la convertie en String JAVA, et l'assigne nom. La deuxime ligne de code, prend la
valeur contenue dans la deuxime colonne de la ligne courante de rs, la convertie en float JAVA, et
l'assigne prix.
Notez que le nombre de la colonne rfre au numro de la colonne dans le resultset, pas dans la table
originale.
En rsum, JDBC vous autorise utiliser le nom de la colonne ou son numro comme argument dans une
mthode getXXX. Utiliser le numro de colonne est un peu plus pratique, mais dans certains cas, le nom de
la colonne est requis. En gnral, fournir le nom de la colonne est essentiellement quivalent fournir son
numro.
Grce la mthode getXXX de JDBC, vous pouvez alors accder aux diffrents types de donnes SQL. Par
exemple, la mthode getInt peut tre utilise pour accder aux types numriques, ou caractres. Mais il
est recommand de n'utiliser getInt que pour accder des donnes SQL de type INTEGER. Il ne peut
pas tre utilis pour rapporter des donnes de type BINARY, VARBINARY, LONGVARBINARY,
DATE, TIME ou TIMESTAMP.
Vous trouverez les types et les mthodes getXXX dans le support de cours la diapo 32, et aussi ici :
http://java.sun.com/docs/books/tutorial/jdbc/basics/retrievingTable.html
Remarque : un resultset peut tre ferm s'il n'est plus utilis : rs.close();

6) Mettre jours les tables


Supposons qu'aprs la premire semaine, le propritaire du "The Coffee Break" veuille mettre jour la
colonne VENTES de la table CAFES en entrant le nombre de livres vendues pour chaque type de caf.
L'instruction SQL pour mettre jour est la suivante :
String updateString = "UPDATE CAFES"
+ " SET VENTES = 75"
+ " WHERE NOM_CAFE LIKE 'Colombian'";

Utilisant l'instruction stmt, le code JDBC excute l'instruction SQL contenue dans updateString :
stmt.executeUpdate(updateString);
7

Polytech'Marseille, Dpartement "Informatique", 4me anne


Bases de donnes

La table CAFES doit maintenant ressembler a :


NOM_CAFE
Colombian
French_Roast
Espresso
Colombian_Decaf
French_Roast_Decaf

FO_ID
101
49
150
101
49

PRIX
7.99
8.99
9.99
8.99
9.99

VENTES
75
0
0
0
0

TOTAL
0
0
0
0
0

Notez que nous n'avons pas encore mis jour la colonne TOTAL, sa valeur est toujours 0.
Maintenant, slectionnons la ligne mise jour, rapportons la valeur dans les colonnes de NOM_CAFE et
de VENTES, et affichons ces valeurs :
String requete = "SELECT NOM_CAFE, VENTES FROM CAFES"
+ " WHERE NOM_CAFE LIKE 'Colombian'";
ResultSet rs = stmt.executeQuery(requete);
while(rs.next()) {
String s = rs.getString("NOM_CAFE");
int n = rs.getInt("VENTES");
System.out.println(n + " livres de" + s + " vendu cette semaine.");
}

a affichera :
75 livres de Colombian vendu cette semaine.

La clause WHERE limite la slection une seule ligne, il n'y avait qu'une seule ligne dans le ResultSet
rs, et donc une seule ligne a t affiche. Dans ce cas, il est possible d'crire le code sans la boucle while :
rs.next();
String s = rs.getString(1);
int n = rs.getInt(2);
System.out.println(n + " livres de " + s + " vendu cette semaine.");

Mme si il n'y a qu'un seul rsultat dans le resultset, vous devez utiliser la mthode next pour y accder.
Maintenant mettons jour la colonne TOTAL en ajoutant le montant hebdomadaire au total existant, et
affichons le nombre de livres vendues ce jour :
String updateString = "UPDATE CAFES"
+ " SET TOTAL = TOTAL + 75"
+ " WHERE NOM_CAFE LIKE 'Colombian'";
stmt.executeUpdate(updateString);
String query = "SELECT NOM_CAFE, TOTAL FROM CAFES"
+ " WHERE NOM_CAFE LIKE 'Colombian'";
ResultSet rs = stmt.executeQuery(query);
while(rs.next()) {
String s = rs.getString(1);
int n = rs.getInt(2);
System.out.println(n+" livres de " + s + " vendu jusqu' maintenant.");
}
8

Polytech'Marseille, Dpartement "Informatique", 4me anne


Bases de donnes

Notez que dans cet exemple, nous utilisons l'indice de la colonne plutt que son nom, fournir l'indice 1
getString (la premire colonne du resultset est NOM_CAFE), et l'indice 2 getInt (la seconde
colonne du resultset est TOTAL). Il est important de faire la distinction entre l'indice d'une colonne dans la
table de la base de donnes comme oppose l'indice dans le resultset. Par exemple, TOTAL est la
cinquime colonne dans la table CAFES mais c'est la seconde colonne dans le rsultat gnr par la requte
dans l'exemple ci-dessus.

Exercice 2
Ecrivez un programme JAVA ralisant l'exemple final de la section 6.

7) Utilisation des PreparedStatement


Parfois, il est plus utile et plus efficace d'utiliser l'objet PreparedStatement pour envoyer une
instruction SQL la base de donnes. Ce type spcial d'instructions est driv de la classe plus gnrale,
Statement, que vous connaissez dj.
Remarque : tout comme un statement, il faut fermer un preparedstatement s'il n'est plus utilis.
7.1 Quand utiliser un objet PreparedStatement
Si vous voulez excuter un objet Statement plusieurs fois, le temps d'excution sera normalement rduit
si vous utilisez la place un objet PreparedStatement.
La fonctionnalit principale d'un objet PreparedStatement, contrairement l'objet Statement, est de
lui fournir une instruction SQL ds sa cration. Ceci a l'avantage dans plusieurs cas, d'envoyer directement
l'instruction SQL au SGBD, o elle y sera compile. Ayant pour rsultat que l'objet PreparedStatement
ne contient plus seulement une instruction SQL, mais bien une instruction SQL prcompile. Cela signifie
que quand le PreparedStatement est excut, le SGBD a juste lancer l'instruction SQL du
PreparedStatement sans avoir le compiler avant.
Un objet PreparedStatement peut tre aussi utilis dans une instruction SQL sans paramtres, mais
vous allez plus probablement les utiliser pour des instructions SQL avec paramtres. L'avantage de ceci,
quand vous utilisez une instruction SQL requrant des paramtres, est que vous pouvez utiliser la mme
instruction en fournissant diffrentes valeurs chaque fois que vous l'excutez. Nous allons voir un
exemple dans la prochaine section.
7.2 Crer un objet PreparedStatement
Tout comme l'objet Statement, vous devez crer l'objet PreparedStatement avec une mthode
Connexion. Utilisant notre prcdente connexion ouverte conn, vous aurez crire un code ressemblant
celui ci-dessous pour crer un objet PreparedStatement recevant deux paramtres.
PreparedStatement updateVentes =
conn.preparedStatement("UPDATE CAFES SET VENTES = ? WHERE NOM_CAFE LIKE ?");

La variable updateVentes contient maintenant une instruction SQL, "UPDATE CAFES SET VENTES =
? WHERE NOM_CAFE LIKE ?", qui a t envoye SGBD puis prcompile.

Polytech'Marseille, Dpartement "Informatique", 4me anne


Bases de donnes

7.3 Paramtres vers un PreparedStatement


Vous devez fournir des valeurs pour tre utilises la place des points d'interrogation, s'il y en a, avant que
vous puissiez excuter un objet PreparedStatement. Pour faire a, il faut utiliser l'une des mthodes
setXXX dfinies dans la classe PreparedStatement. Si la valeur que vous voulez substituer au point
d'interrogation est un int JAVA, vous devez appeler la mthode setInt. Si la valeur est un String
JAVA, vous devez appeler la mthode setString, et ainsi de suite. En gnral, il y a un setXXX pour
chaque type JAVA.
En utilisant l'objet PreparedStatement de l'exemple prcdant, la ligne de code qui remplace le point
d'interrogation en un int JAVA ayant la valeur 75 :
updateVentes.setInt(1,75);

Comme vous pouvez le voir dans l'exemple, le premier argument donn la mthode setXXX est la
position du point d'interrogation, et le deuxime argument, la valeur par laquelle on veut le remplacer.
L'exemple suivant substitue le deuxime paramtre avec le string "Colombian".
updateVentes.setString(2, "Colombian");

Aprs que ces valeurs aient t dposes dans les deux paramtres d'entres, l'instruction SQL contenue
dans updateVentes sera quivalente l'instruction SQL dans l'objet String updateString que nous
avons utilis dans un des exemples prcdents. Les deux fragments de codes suivants font la mme chose :
Code 1 :
String updateString = "UPDATE CAFES SET VENTES = 75"
+ " WHERE NOM_CAFE LIKE 'Colombian'";
stmt.executeUpdate(updateString);

Code 2 :
PreparedStatement updateVentes =
conn.preparedStatement("UPDATE CAFES SET VENTES = ? WHERE NOM_CAFE LIKE ?");
updateVentes.setInt(1,75);
updateVentes.setString(2, "Colombian");
updateVentes.executeUpdate();

Nous avons utilis la mthode executeUpdate pour excuter les objets Statement stmt et
PreparedStatement updateVentes. Remarquez qu'aucun argument n'est fourni executeUpdate
quand ils sont utiliss pour excuter updateVentes. Et ceci est juste, car updateVentes contient dj
l'instruction SQL devant tre excute.
Prtez attention ces exemples, vous verrez pourquoi vous devrez utiliser un objet PreparedStatement
avec paramtres, plus qu'une simple instruction, et ce, mme si elle ncessite moins d'tapes.
Si vous mettez une ou deux fois jours la colonne VENTES, cela ne vaut pas la peine d'utiliser une
instruction SQL avec paramtres. Mais si vous la mettez souvent jours, il sera plus simple d'utiliser un
objet PreparedStatement, spcialement en situation o vous avez utiliser une boucle for ou une
boucle while pour dfinir un paramtre une succession de donnes. Nous allons voir un exemple plus tard
dans cette section.
Une fois qu'on a assign une valeur un paramtre, il retiendra la valeur jusqu' ce qu'elle soit rinitialise
avec une autre valeur, ou bien jusqu' ce que la mthode clearParameters soit appele. Utilisant l'objet
PrepareStatement updateVentes. Le code suivant illustre la rutilisation d'un preparedstatement
aprs avoir rinitialis la valeur de l'un des paramtres et en conservant la valeur de l'autre paramtre :
10

Polytech'Marseille, Dpartement "Informatique", 4me anne


Bases de donnes

updateVentes.setInt(1, 100);
updateVentes.setString(2, "French_Roast");
updateVentes.executeUpdate();
//Change la valeur de VENTES la ligne French Roast pour la valeur 100
updateVentes.setString(2, "Espresso");
updateVentes.executeUpdate();
//Change la valeur de la colonne VENTES la ligne Espresso pour la valeur 100
//(le premier paramtre est rest 100, et le second paramtre est
//rinitialis par "Espresso")

7.4 Utilisation d'une boucle pour assigner des valeurs


Vous pouvez souvent rendre le code plus facile en utilisant une bouche for ou while pour assigner des
valeurs aux paramtres d'entres.
Le fragment de code qui suit prsente l'utilisation d'une boucle for pour assigner des valeurs aux
paramtres dans un objet PreparedStatement updateVentes. Le tableau VentesDeLaSemaine
contient les montants des ventes hebdomadaires. Ces montants de ventes correspondent aux noms des cafs
lists dans le tableau cafe, donc le premier montant dans VentesDeLaSemaine(175) s'applique au
premier caf dans cafe (" Colombian "), le second montant dans VentesDeLaSemaine (150)
s'applique au second caf dans cafe (" French_Roast "), et ainsi de suite. Ce fragment de code prsente la
mise jour de la colonne VENTES pour tous les cafs de la table CAFES :
PreparedStatement updateVentes;
String updateString = "update CAFES"
+ "set VENTES = ? WHERE NOM_CAFE LIKE ?";
updateVentes = conn.prepareStatement(updateString);
int [] VentesDeLaSemaine = {175, 150, 60, 155, 90};
String [] cafes = {"Colombian", "French_Roast", "Espresso", "Colombian_Decaf",
"French_Roast_Decaf"};
int len = cafes.length;
for(int i = 0 ; i < len ; i ++) {
updateVentes.setInt(1, VentesDeLaSemaine[i]);
updateVentes.setString(2, cafes[i]);
updateVentes.executeUpdate();
}

Quand le propritaire dsire faire une mise jour sur les montants des ventes de la semaine suivante, il peut
utiliser ce code comme modle. Il ne lui reste plus qu' entrer de nouveaux montants de vente dans l'ordre
adquat dans le tableau VentesDeLaSemaine. Le nom du caf dans le tableau cafe reste constant, donc
il n'a pas besoin d'y apporter de modifications. (Dans une vraie application, les valeurs seraient
probablement entres par l'utilisateur plutt que d'tre initialises dans le tableau)

Exercice 3
Ecrivez un programme JAVA ralisant l'exemple prcdent (section 7.4).

11

Polytech'Marseille, Dpartement "Informatique", 4me anne


Bases de donnes

7.5 Valeurs retournes par la mthode executeUpdate


La mthode executeQuery retourne un objet ResultSet contenant les rsultats de la requte envoye au
SGBD, la valeur retourne pour executeUpdate est un int qui indique combien de lignes de la table ont
t mises jour. Le code qui suit montre la valeur retourne par executeUpdate en l'assignant la
variable n :
updateVentes.setInt(1,50);
updateVentes.setString(2, "Espresso");
int n = updateVentes.executeUpdate(); //n vaut 1 car une ligne concerne.

La table CAFES a t mise jour en remplaant la valeur contenue dans la colonne VENTES de la ligne
Espresso par 50. La mise jour affecte une seule ligne dans la table, donc n est gal 1.
Quand la mthode executeUpdate est utilise pour excuter une instruction DDL, comme crer une
table, elle retourne la valeur 0. Dans le fragment de code suivant, qui excute une instruction DDL pour
crer la table CAFES, n recevra la valeur 0 :
int n = executeUpdate(createTableCafe); // n vaut 0

Notez que quand la valeur retourne de executeUpdate est 0, cela peut vouloir dire deux choses :
- soit l'instruction excute est une mise jour et que 0 ligne est affect.
- soit l'instruction est une instruction DDL.

8) Utiliser les jointures


Avant d'aller plus loin, nous devons crer la table FOURNISSEURS et la remplir de ses valeurs.
Le code ci-dessous crera la table FOURNISSEURS :
String createFournisseurs = "create table FOURNISSEURS ("
+ " FO_ID INTEGER, NOM_FO VARCHAR(40), RUE VARCHAR(40), "
+ " VILLE VARCHAR(20), ETAT CHAR(2), CODE_POSTAL CHAR(5))";
stmt.executeUpdate(createFournisseurs);

Le code suivant insre les lignes pour les trois fournisseurs dans FOURNISSEURS :
stmt.executeUpdate("insert into FOURNISSEURS values (101,'Acme, Inc.',"
+ " '99 Market Street', 'Groundsville', 'CA', '95199')");
stmt.executeUpdate("insert into FOURNISSEURS values (49,'Superior Coffee',"
+ " '1 Party Place', 'Mendocino', 'CA','95460')");
stmt.executeUpdate("insert into FOURNISSEURS values (150,'The High Ground',"
+ " '100 Coffee Lane', 'Meadows', 'CA','93966')");

Exercice 4
Ecrivez un programme JAVA crant la table FOURNISSEURS et ajoutant les trois fournisseurs.
Maintenant que nous avons les tables CAFES et FOURNISSEURS, nous pouvons procder au scnario ou
le propritaire de "The Coffee Break" veut obtenir la liste des cafs qu'il a achets auprs d'un fournisseur
en particulier.
12

Polytech'Marseille, Dpartement "Informatique", 4me anne


Bases de donnes

Exercice 5
Ecrivez un programme donnant la liste des cafs achets auprs d'un fournisseur dont le nom est donn en
paramtre du programme.
Exemple de rsultat produire :
Le(s) caf(s) achet(s) Acme, Inc. :
Colombian
Colombian_Decaf

A prsent, vous connaissez les bases de JDBC. Les deux sections qui suivent correspondent des notions
avances : les transactions et les procdures stockes.

9) Transactions
Parfois, vous ne voulez pas qu'une instruction prenne effet sans qu'une autre lui succde. Par exemple,
quand le propritaire du "The Coffee Break" met jour le montant de caf vendu chaque semaine, il
aimerait aussi mettre jour le montant total des ventes jusqu' maintenant. Donc, il ne veut pas mettre
jour l'un sans mettre jour l'autre, sinon les donnes ne seraient pas cohrentes. La manire pour tre sr
que toutes les actions et interactions voulues s'effectuent est d'utiliser une transaction. Une transaction est
un jeu d'une ou plusieurs instructions qui sont excutes ensembles de faon unitaire, donc toutes les
instructions sont excutes, ou aucune.
9.1 Dsactiver le mode Auto-commit
Quand une connexion est cre, elle est en mode auto-commit. Ce qui veut dire que chaque instruction
SQL est traite comme une transaction et prendra automatiquement effet aprs sa bonne excution. (Pour
tre plus prcis, une instruction SQL prend automatiquement effet sur la base de donnes lorsqu'elle est
termine, et non pas quand elle est excute). Une instruction est termine quand tous ses rsultats et toutes
ses mises jour ont t rapports. La manire d'autoriser deux ou plusieurs instructions tre groupes
dans une transaction est de mettre hors service le mode auto-commit. Si conn est notre connexion active,
nous avons alors :
conn.setAutoCommit(false);

9.2 Pour que la transaction prenne effet sur la BD


Une fois que le mode auto-commit est dsactiv, aucune instruction SQL ne prendra effet jusqu' ce que la
mthode commit soit appele. Le code qui suit, o conn est la connexion active, illustre la transaction :
conn.setAutoCommit(false);
PreparedStatement updateVentes =
conn.prepareStatement("UPDATE CAFES SET VENTES = ? WHERE NOM_CAFE LIKE ?");
updateVentes.setInt(1,50);
updateVentes.setString(2, "Colombian");
updateVentes.executeUpdate();
PreparedStatement updateTotal = conn.prepareStatement(
"UPDATE CAFES SET TOTAL = TOTAL + ? WHERE NOM_CAFE LIKE ?");
updateTotal.setInt(1,50);
updateTotal.setString(2,"Colombian");
updateTotal.executeUpdate();

13

Polytech'Marseille, Dpartement "Informatique", 4me anne


Bases de donnes

conn.commit();
conn.setAutoCommit(true);

Quand la mthode commit est appele (automatiquement quand auto-commit est active ou explicitement
quand il est dsactiv), tous les changements rsultants des instructions de la transaction seront permanents.
Dans ce cas, cela signifie que les colonnes VENTES et TOTAL pour le caf Colombian ont t modifies
50 (si TOTAL tait 0) et retiendra cette valeur jusqu' ce qu'elle soit modifie par une instruction.
La dernire ligne de l'exemple prcdent active le mode auto-commit, ce qui veut dire que chaque
instruction prend ds lors effet automatiquement sur la base de donnes quand elle est termine. Vous
revenez donc l'tat par dfaut, celui o vous n'avez plus appeler la mthode commit. Il est conseill de
dsactiver le mode auto-commit uniquement quand vous tes en mode transaction. De cette faon, vous
rduisez les chances de conflit au niveau des entres dans la base de donnes avec les autres utilisateurs.

Exercice 6 (facultatif)
Ecrivez un programme JAVA correspondant l'exemple prcdent.

9.3 Utiliser les transactions pour prserver l'intgrit des donnes


En plus de grouper les instructions ensembles pour tre excutes unitairement, les transactions peuvent
aider prserver l'intgrit de donnes dans une table. Par exemple, imaginons qu'un employ tait suppos
entrer les nouveaux prix du caf dans la table CAFES, mais ne l'a pas fait depuis quelques jours. Pendant
ce temps, les prix ont augments, et le propritaire dcide de mettre jour les nouveaux prix dans la table.
L'employ se dcide finalement entrer les prix n'tant plus jour dans la base de donnes en mme temps
que le propritaire met jour la table. Aprs avoir insrer les prix non jour, l'employ ralise qu'ils ne
sont plus valides, et donc appelle la mthode rollback de l'objet Connexion afin d'annuler les effets de
ses manipulations. (La mthode rollback met fin une transaction et restaure les valeurs prsentes avant
qu'elles aient t mises jour). Mais en mme temps, le propritaire excute une instruction SELECT puis
affiche les nouveaux prix. Dans cette situation, il est possible que les prix affichs par le propritaire
proviennent d'un rollback contenant les anciens prix, rendant l'affichage des prix incorrects.
Ce genre de situation peut tre vit en utilisant les transactions. Si un SGBD supporte les transactions, et
la plupart le font, il fournira certains niveaux de protection contre les conflits qui peuvent survenir quand
on accde des donnes au mme moment.
Pour viter les conflits durant une transaction, un SGBD utilise des verrous, mcanisme bloquant l'accs
aux donnes utilises par la transaction aux autres utilisateurs. Une fois qu'un verrou est pos, il restera en
place jusqu' ce qu'une transaction soit envoye vers la base de donnes pour qu'elle puisse y prendre effet,
ou vers un rollback. Par exemple, un SGBD pourra verrouiller la ligne d'une table jusqu' ce que les
mises jour aient t valides. L'effet de ce verrou peut tre de prvenir un utilisateur contre les valeurs
errones.
La manire dont les verrous sont poss dtermine le niveau d'isolation de la transaction, pouvant aller
jusqu' bloquer totalement les transactions.
Un exemple de niveau d'isolation de transaction est TRANSACTION_READ_COMMITTED qui
n'autorise l'accs aucune valeur jusqu' ce qu'elles aient t valides dans la base de donnes. En d'autre
terme, si le niveau d'isolation de la transaction est TRANSACTION_READ_COMMITED, le SGBD ne
permettra donc pas de pouvoir lire des valeurs errones. L'interface Connexion inclue cinq niveaux
d'isolation que vous pourrez utiliser avec JDBC.
Normalement, vous pouvez toujours utiliser celui par dfaut de votre SGBD. JDBC vous permet de savoir
quel niveau d'isolation votre SGBD utilise (par le biais de la mthode getTransactionIsolation) et
vous permet aussi de dfinir un autre niveau que celui utilis (grce setTransactionIsolation).
Gardez l'esprit que mme si JDBC vous permet de dfinir un niveau de transaction, il faut quand mme
que les drivers utiliss et le SGBD utilis le supporte.
14

Polytech'Marseille, Dpartement "Informatique", 4me anne


Bases de donnes

9.4 Quand appeler la mthode RollBack


Comme mentionn plus tt, appeler la mthode rollback annule une transaction et remet les valeurs qui
ont t modifies leurs valeurs originales. Si vous essayez d'excuter une ou plusieurs instructions dans
une transaction et que vous avez une SQLException, vous devez utiliser la mthode rollback pour
annuler la transaction et la recommencer depuis le dbut. C'est la seule faon d'tre sr de ce qui a t pris
en compte sur la base de donnes et ce qui ne l'a pas t. Une SQLException vous indique que quelque
chose ne fonctionne pas, mais elle ne vous indique pas ce qui t pris en compte ou pas. Donc vous ne
pouvez pas compter sur le fait que rien n'a t mis jour sur la BD, appeler la mthode rollback est la
seule faon d'en tre sr.

10) Procdures stockes


Une procdure stocke est un groupe d'instructions SQL qui forme une unit logique et effectue une tche
particulire. Les procdures stockes sont utilises pour encapsuler un jeu d'oprations ou de requtes
excuter sur un serveur de base de donnes. Par exemple, les oprations sur une base de donnes
d'employes (embauche, augmentation, etc.) peuvent tre codes en procdures stockes puis excutes.
Elles peuvent tre compiles puis excutes avec diffrents paramtres et diffrents rsultats, et elles
possdent plusieurs combinaisons d'entres, de sorties et de paramtres entres/sorties.
Les procdures stockes sont supportes par la plupart des SGBD, mais il y a quand mme quelques
variations dans leur syntaxe. Pour cette raison, nous vous montrons un simple exemple de procdure
stocke et comment l'invoquer avec JDBC, mais cet exemple n'est pas fait pour tre excut.
10.1 Instructions SQL pour crer des procdures stockes
Cette section traite des procdures stockes trs simplistes sans paramtres. Mme si les procdures
stockes effectuent gnralement des tches bien plus complexes que celles prsentes dans cet exemple, il
sert tout de mme illustrer certains points leurs propos. Comme nous l'avons dit prcdemment, la
syntaxe est diffrente pour chaque SGBD. Par exemple, certains utilisent begin ... end ou d'autres
mots-cls pour indiquer le commencement et la fin de la dfinition de la procdure.
Pour ORACLE, cette instruction crera une procdure stocke :
CREATE PROCEDURE SHOW_FOURNISSEURS ()
AS BEGIN
SELECT FOURNISSEURS.NOM_FO, CAFES.NOM_CAFE
FROM FOURNISSEURS, CAFES
WHERE FOURNISSEURS.FO_ID = CAFES.FO_ID
ORDER BY NOM_FO
END;

Le code qui suit met l'instruction SQL dans une chane de caractres et l'assigne la variable
createProcedure, que nous utiliserons plus tard :
String createProcedure = " CREATE PROCEDURE SHOW_FOURNISSEURS ()"
+ " AS BEGIN"
+ " SELECT FOURNISSEURS.NOM_FO, CAFES.NOM_CAFE"
+ " FROM FOURNISSEURS, CAFES"
+ " WHERE FOURNISSEURS.FO_ID = CAFES.FO_ID"
+ " ORDER BY NOM_FO"
+ " END";

15

Polytech'Marseille, Dpartement "Informatique", 4me anne


Bases de donnes

Le fragment de code suivant utilise l'objet Connexion conn pour crer un objet Statement, qui sera
utilis pour envoyer l'instruction SQL afin de crer la procdure stocke sur la base de donnes :
Statement stmt = conn.createStatement();
stmt.executeUpdate(createProcedure);

La procdure SHOW_FOURNISSEURS sera compile et stocke dans la base de donnes comme un objet
pouvant tre appel de faon similaire l'appel d'une mthode.
10.2 Appeler une procdure stocke avec JDBC
JDBC vous permet d'appeler une procdure stocke sur la base de donnes depuis une application crite en
JAVA. La premire tape est de crer un objet CallableStatement. Comme avec les objets
Statement et PreparedStatement, ceci est fait avec une connexion ouverte. Un objet
CallableStatement contient l'appel d'une procdure, il ne contient pas la procdure elle-mme. La
premire ligne de code ci-dessous cre un appel la procdure stocke SHOW_FOURNISSEURS en
utilisant la connexion conn. La partie qui est entre accolade est la syntaxe pour la procdure stocke.
Quand le driver rencontre "{call SHOW_FOURNISSEURS}", il traduira cette syntaxe en SQL natif utilis
par la base de donnes pour appeler la procdure stocke nomme SHOW_FOURNISSEURS :
CallableStatement cs = conn.prepareCall("{call SHOW_FOURNISSEURS}");
ResultSet rs = cs.executeQuery();

Notez que la mthode pour excuter cs est executeQuery car cs appelle une procdure stocke qui
contient une requte et produit un resultset. Si la procdure avait contenue une mise jour ou une des
instructions DDL, la mthode executeUpdate aurait t utilise. Comme c'est parfois le cas, une
procdure stocke contient plus d'une instruction SQL, qui pourrait produire plus d'un resultset, plus d'une
mise jour, ou une combinaison de resultsets et de mise jour. Dans ce cas, lorsqu'il y a de multiples
rsultats, la mthode execute devra tre utilise pour excuter CallableStatement.
La classe CallableStatement est une classe drive de PrepareStatement, donc un objet
CallableStatement peut avoir des paramtres d'entres tout comme l'objet PreparedStatement. En
plus, un objet CallableStatement peut avoir des paramtres de sorties ou des paramtres qui sont fait
pour l'entre et la sortie. Les paramtres INOUT et la mthode execute sont rarement utiliss.

16

Polytech'Marseille, Dpartement "Informatique", 4me anne


Bases de donnes

ANNEXE
Exemple de programme utilisant JDBC :
(disponible ici : http://nicolas.durand.perso.luminy.univmed.fr/pub/bd/tpjdbc/Test.java)
import java.sql.*;
public class Test {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
int i = -1;
String s = null;
float f = -1;
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
}
catch (ClassNotFoundException e) {
System.err.println("Erreur lors du chargement du pilote : " + e.getMessage());
e.printStackTrace();
}
try {
conn =
DriverManager.getConnection("jdbc:oracle:thin:@pedaserv1.luminy.univmed.fr:1521",
"compteN","compteN");
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT a, b, c FROM Table");
while(rs.next()) {
i = rs.getInt("a");
s = rs.getString("b");
f = rs.getFloat("c");
System.out.println(i+"\t"+s+"\t"+f);
}
}
catch(SQLException e2) {
System.err.println("Erreur : " + e2.getMessage());
e2.printStackTrace();
}
finally {
try {
if(rs != null) rs.close();
if(stmt != null) stmt.close();
if(conn != null) conn.close();
}
catch(SQLException e3) {
System.err.println("Erreur lors de la fermeture des ressources : "
+ e3.getMessage());
e3.printStackTrace();
}
}
}
}

Autre exemple : http://nicolas.durand.perso.luminy.univmed.fr/pub/bd/tpjdbc/VolsParisMarseille.java


17