Java : Fonctions Avancées et Multitâche
Java : Fonctions Avancées et Multitâche
COURS
Java – Notions avancées
Description courte
Auteur Version - Date Nom du fichier
G.VALET Version 2.4 - Mai 2003 Cours N°3 - Fonctions avancées JAVA - IRIS.docx
Apprentissage des notions avancées du langage : Les flux, les threads, les bases de données, la programmation
réseau
COURS Java – Notions avancées
A. Sommaire
A. SOMMAIRE .............................................................................................................................................................. 2
CHAPITRE 1 : ACCES AUX FLUX ET AUX FICHIERS ................................................................................................... 5
A. INTRODUCTION ......................................................................................................................................................... 5
B. LES CLASSES INPUTSTREAM, OUTPUTSTREAM ................................................................................................................. 5
B.1. Modèle objet ................................................................................................................................................ 5
B.2. Ecriture et lecture ......................................................................................................................................... 6
B.3. Lire/Ecrire dans des fichiers .......................................................................................................................... 7
B.4. Lire/Ecrire des données numériques ............................................................................................................. 7
B.5. Chaînage des flux filtrés ............................................................................................................................... 8
C. LES CLASSES READER ET WRITER ................................................................................................................................... 9
C.1. Flux de caractères ......................................................................................................................................... 9
C.2. Saisie de caractères au clavier .................................................................................................................... 10
C.3. Types de codage de caractères ................................................................................................................... 10
C.4. Fichiers ........................................................................................................................................................ 10
C.5. Flux de sortie de texte ................................................................................................................................. 10
C.6. Flux d'entrée de texte ................................................................................................................................. 11
D. LES EXCEPTIONS ...................................................................................................................................................... 11
D.1. Lecture dans un fichier ............................................................................................................................... 11
D.2. Ecriture dans un fichier ............................................................................................................................... 12
E. LES FICHIERS ZIP ..................................................................................................................................................... 14
E.1. Principe de lecture ...................................................................................................................................... 14
E.2. Exemple complet......................................................................................................................................... 15
E.3. Principe d'écriture ....................................................................................................................................... 17
CHAPITRE 2 : PROGRAMMATION MULTITACHES AVEC LES THREADS ...................................................................17
A. INTRODUCTION ....................................................................................................................................................... 17
A.1. Programmation multitâche ........................................................................................................................ 17
A.2. Threads et processus .................................................................................................................................. 18
A.3. Le "faux multitâche" ................................................................................................................................... 18
B. UTILISER LES THREADS .............................................................................................................................................. 18
B.1. Qu'est-ce qu'un thread ............................................................................................................................... 18
B.2. Un exemple de thread ................................................................................................................................ 18
B.3. L'objet thread ............................................................................................................................................. 19
B.4. Exécution de plusieurs threads ................................................................................................................... 21
C. PROPRIETES DES THREADS ......................................................................................................................................... 21
C.1. Etats des threads ........................................................................................................................................ 21
C.2. Thread bloqué ............................................................................................................................................. 21
C.3. Thread mort (Deadlock) .............................................................................................................................. 22
C.4. Interrompre un thread ................................................................................................................................ 22
C.5. Priorités d'un thread ................................................................................................................................... 23
C.6. Threads égoïstes ......................................................................................................................................... 23
C.7. Constructeurs et méthodes de la classe Thread ......................................................................................... 23
D. EXEMPLE COMPLET .................................................................................................................................................. 26
D.1. Présentation ............................................................................................................................................... 26
D.2. Code source ................................................................................................................................................ 27
E. GROUPES DE THREADS .............................................................................................................................................. 30
E.1. Construire un groupe de threads ................................................................................................................ 31
E.2. Interrompre les threads d'un groupe .......................................................................................................... 31
E.3. Connaître les threads actifs ........................................................................................................................ 31
F. SYNCHRONISATION................................................................................................................................................... 32
F.1. Présentation du problème .......................................................................................................................... 32
F.2. mot clé synchronised .................................................................................................................................. 32
COURS Java – Notions avancées
1
ANSI : Norme de codage des caractères sur 2 octets
COURS Java – Notions avancées
La lecture ou l'écriture peut également se faire par ensemble d'octets à l'aide des tableaux. Les
méthodes read et write ne sont plus abstraites :
public void write( byte[] b) throws IOException
ou
public int read( byte [] b ) throws IOException
double s = dis.readDouble();
Cet enchaînement va vous permettre d'associer les différents types de flux de manière à
bénéficier de leurs fonctionnalités. En effet, partons du principe que DataInputStream sait lire
des numériques et FileInputStream sait lire dans des fichiers et associons les pour qu'ils nous
fassent partager leurs compétences propres.
Dans notre exemple, si nous souhaitons qu'en plus de lire des données numériques dans des
fichiers, nous souhaitions que cette lecture soit bufferisée2 , il suffirait d'associer à nos 2 objets
précédent, un 3ème issu de la classe BufferedInputStream . L'exemple suivant nous montre
l'enchaînement de la construction :
DataInputStream dis = new DataInputStream
(new BufferedInputStream
( new FileInputStream("fiche.dat") ));
L'objet de type DataInputStream est en haut de la chaîne de flux puisque ses méthodes d'accès
aux données nous serons utiles pour lire des données de type numériques.
La méthode read() de l'objet dis va procéder à une lecture bufferisée dans le flux.
Cette syntaxe n'est pas très conviviale mais l'empilement des constructeurs est un passage obligé
pour arriver à obtenir un flux avec de telles fonctionnalités.
Pour finir, voici un dernier exemple permettant de lire un booléen dans un fichier ZIP:
ZipInputStream zis = new ZipInputStream(
new FileInputStream("fiche.zip") );
DataInputStream dis = new DataInputStream(zis);
Pour lire un booléen dans ce fichier ZIP, on utilise :
boolean b = dis.readBoolean();
2
bufferiser : Action de lire un ensemble de données simultanément dans un flux et de les stocker temporairement
jusqu'à leur traitement. L'avantage est que l'accession aux données ne s'effectue qu'une seule fois par opposition à
une lecture non bufferisée où la lecture de chaque élément nécessite un accès dédié et coûteux en mémoire.
COURS Java – Notions avancées
3
UNICODE : Système de codage sur 16 bits des caractères opposé à la norme ANSI sur 8 bits
COURS Java – Notions avancées
C.4. Fichiers
Il existe un type particulier pour lire et écrire dans des fichiers. Il s'agit des classes FileWriter et
FileReader. Ces sont en fait un objet de type OutputStreamWriter associé à un objet de type
FileOutputStream. Les deux programmes suivant sont identiques :
FileWriter fw = new FileWriter("data.txt");
ou
OutputStreamWriter fw = new OutputStreamWriter(
new FileOutputStream("data.txt") ) ;
Les classes FileWriter et FileReader sont des classes d'aide permettant d'obtenir un flux de
caractères facilement.
L'intérêt du code précédent est de pouvoir disposer de toutes les méthodes telles que print,
println , tout comme l'objet System.out. Ces méthodes permettent d'envoyer tout type de
données primitifs tels que int, char, String ..
Selon les systèmes hôtes, les caractères de fin de lignes varient ( \r\n pour Windows , \n pour
UNIX, \r pour Macintosh. Pour résoudre ce problème, JAVA propose un appel à la méthode
System.getProperty("line.separator") qui renvoie les caractères correspondant à la plate-forme
d'exécution
Pour lire autre chose que des caractères, il faut convertir les caractères obtenus grâce aux
méthodes de conversion des objets :
String s = br.readline();
double x = Double.parseDouble(s);
La méthode statique parseDouble permet de convertir une chaîne en un Double.
D. Les exceptions
Bien entendu, comme la lecture ou l'écriture dans un flux n'est jamais sûre, les objets
permettant l'accès à ces flux respectent le mécanisme des exceptions, au cas où la lecture ou
l'écriture échouerait.
} catch ( FileNotFoundException fe ) {
System.out.println("Fichier introuvable");
COURS Java – Notions avancées
} catch (IOException e) {
System.out.println("Erreur d'E/S");
}
La méthode read de l'objet FileReader renvoie –1 si la fin du fichier est atteinte. La chaîne
fileString contient alors l'ensemble du fichier. Vous remarquerez que la méthode read renvoie
un entier qu'il faut convertir en caractère pour le traiter.
Les exceptions levées sont de type IOException et FileNotFoundException. Elles correspondent
aux erreurs courantes se produisant au niveau des fichiers.
} catch (IOException e) {
System.out.println("Erreur d'E/S");
}
Vous noterez que les mêmes exceptions sont levées pour l'écriture.
Le répertoire utilisé pour lire et écrire dans des fichiers si aucun chemin n'est spécifié, est le
répertoire courant correspondant au répertoire d'où le programme a été exécuté. Pour obtenir le
chemin complet, vous pouvez faire appel à la méthode statique getProperty("user.dir") de la
classe System. Attention cependant à cette méthode qui peut envoyer des exceptions si la
propriété n'existe pas ou encore si la sécurité est activée et empêche le programme d'accéder à
ces propriétés.
La plupart du temps, la classe chargée d'ouvrir les fichiers et la classe chargée d'informer
l'utilisateur en cas d'échec n'étant pas la même, il devient indispensable de renvoyer les
exceptions au code appelant :
try {
fw = new FileWriter("data.txt");
int i=0;
for (int i=0 ; i< chaine.length() ; i++)
fw.write(chaine.substring(i,i+1));
fw.close();
} catch ( FileNotFoundException fe ) {
System.out.println("Fichier introuvable");
throw fe;
} catch (IOException e) {
System.out.println("Erreur d'E/S");
COURS Java – Notions avancées
throw e;
}
COURS Java – Notions avancées
Pour lire dans une entrée, vous éviterez de vous servir de la méthode read qui ne fourni aucun
formatage. Les méthodes spécifiques d'un flux filtré seront plus apropriées. Par exemple, pour
lire un fichier texte se trouvant dans un fichier ZIP :
BufferedReader in = new BufferedReader(
new InputStreamReader(zin));
String s;
while (( s= in.readline()) != null )
… Traitement de la ligne
4
RFC : Request For Comment , groupes de travail précisant les normes de tous les protocoles et langages
concernant l'informatique.
COURS Java – Notions avancées
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.util.zip.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
fileList.addActionListener(this);
scanZipFile();
}
}
else if (source == exitItem) System.exit(0);
else if (source == fileList)
loadZipFile((String)fileList.getSelectedItem());
}
63-76 : Parcours du fichier ZIP (Lecture) à partir d'un flux filtré composé d'un
ZipInputStream et d'un FileInputStream.
78-97 : Lecture de l'entrée avec le même flux filtré mais pour chaque entrée,
utilisation d'un autre flux filtré composé d'un BufferedReader et d'un
COURS Java – Notions avancées
5
OS : Operating System – Système d'exploitation
COURS Java – Notions avancées
6
GUI : Graphic User Interface – Interface graphique utilisateur
COURS Java – Notions avancées
ad N °1 page.htm l
T h re
T éléch argem en t
A fficha ge
im g 1.jp g
ad N °2
T h re
T éléch argem en t
A fficha ge
a d N °3
im g 2.jp g T hre
T éléch argem en t
A fficha ge
im g 3.jp g
La deuxième solution s'avère irréaliste étant donné que la plupart du temps, vos propres classes
hériteront déjà d'une autre classe et par conséquent, ne pourront pas hériter de plusieurs classes.
En JAVA, l'héritage multiple n'est pas supporté. Néanmoins, si votre classe n'hérite d'aucune
autre, il est préférable de la faire hériter de la classe Thread
Voici un diagramme objet représentant le cas de figure le plus courant où l'objet devant
s'exécuter comme un thread implémente l'interface Runnable et hérite de sa classe parent.
COURS Java – Notions avancées
35 // Champs
Thread th;
…
36 // Constructeurs
public ThreadedClass() {
th = new Thread(this); // Lie la classe avec le thread qu'elle
// contient
th.start(); // Démarre le thread
…
37 // Méthodes
public void run() { // Méthode appelée par start()
… Processus d'exécution
th.sleep(100); //Met le thread en sommeil pendant 100ms
}
}
Code partiel de l'utilisation d'un thread
COURS Java – Notions avancées
Thread 1 Thread 1
Thread 2 Thread 2
Thread 3
Un thread bloqué peut uniquement être activé par la même technique que celle qui l'a bloqué.
Par exemple, un thread bloqué par une opération d'entrée-sortie devra attendre que celle-ci se
termine. De même qu'un thread bloqué par la méthode sleep devra attendre le délai passé en
argument.
try {
while ( aucune requête de fin && encore du travail à faire)
{ Travail à faire
}
} catch ( InterruptedException )
{ // Le thread a été interrompu pendant sleep ou wait
}
}
Si la méthode interrupt a été appelée pendant que le thread n'était pas bloqué, aucune
exception de type InterruptException n'est générée. Le thread doit alors appeler la
méthode interrupted pour déterminer s'il a été interrompu.
try {
while ( encore du travail à faire && !interrupted())
{ Travail à faire }
COURS Java – Notions avancées
} catch ( InterruptedException )
{ // Le thread a été interrompu pendant sleep ou wait }
}
Si plusieurs thread exécutables ont la même priorité, c'est au système de gestion des
threads de décider lequel de ces threads va être exécuté. Le problème est que, d'un
système à l'autre, ce choix peut-être différent. Voici une des faiblesses du langage JAVA
qui signifie qu'on ne peut pas être sûr que les programmes multithread s'exécuteront de
la même façon sur toutes les plate formes.
Constructeurs de Thread
Thread()
Crée un nouveau thread.
Thread(Runnable target)
Crée un nouveau Thread relatif à l'objet implémentant l'interface Runnable
Thread(Runnable target, String name)
Crée un nouveau Thread relatif à l'objet implémentant l'interface Runnable avec
un nom
Thread(String name)
Crée un nouveau Thread avec un nom
Thread(ThreadGroup group, Runnable target)
Crée un nouveau Thread relatif à l'objet implémentant l'interface Runnable ,
membre du groupe passé en argument.
COURS Java – Notions avancées
Méthodes de Thread
static int activeCount()
Renvoie le nombre de threads actifs dans le groupe de ce
thread
void checkAccess()
Détermine si le thread actuellement actif a les permissions de
modifier ce thread
static Thread currentThread()
Renvoie la reference au thread actuellement exécuté
String getName()
Renvoie le nom du thread
int getPriority()
Renvoie la priorité de Thread.
ThreadGroup getThreadGroup()
Renvoie le groupe de thread auquel le thread appartient
void interrupt()
Interrompt le thread (DANGEREUX)
static boolean interrupted()
Test si le thread courant a été interrompu
boolean isAlive()
Teste si le thread n'est pas mort
boolean isInterrupted()
Test si ce thread a été interrompu
void join()
Attend que ce thread meurt.
void join(long millis)
Attends au moins millis millisecondes que ce thread meurt
void join(long millis, int nanos)
Même chose mais millis+nanos
void run()
méthode appelée par la méthode start pour démarrer le
thread
void setName(String name)
Change le nom du thread
void setPriority(int newPriority)
Change la priorité du thread
static void sleep(long millis)
Endort le thread pour une durée millis millisecondes
static void sleep(long millis, int nanos)
Endort le thread pour une durée millis millisecondes + nanos
nanonsecondes
COURS Java – Notions avancées
void start()
Démarre le thread et la machine virtuelle appelle la méthode
run
String toString()
Renvoie une représentation chaîne comportant le nom, la priorité
et le groupe auquel appartient le thread
static void yield()
Provoque l'arrêt de l'exécution du thread et autorise les autres
threads à s'exécuter
Liste non exhaustive des méthodes de la classe Thread
D. Exemple complet
D.1. Présentation
Voici l'exemple d'une fenêtre affichant un texte clignotant dès qu'on appui sur un bouton. A
chaque appui sur ce bouton, un thread différent est exécuté :
ThreadFram e.java
- panel : Jpanel
- southPanel : J panel Interface
- sta rtB utton : Jbutton R unna ble
- closeB utton : Jbutton
- threadCo unt : int
+run()
initCom ponents ( ) : void
closeB uttonAc tionPerform ed(Ac tionEv ent) : void
startButtonA ctionP erform ed(A ctionE vent) : void
im plém en te
A un
- threadText : Thread
- x,y : int
- tex te : String
- panel : Jpanel
ThreadText.java
Voici le code source des fichiers ThreadText.java et ThreadFrame.java
x=d.width;
y=d.height;
textThread = new Thread(this);
textThread.start();
}
69 /** Dessine le texte ou l'efface s'il est déjà affiché (Mode XOR)
70 */
public void draw() {
Graphics g = panel.getGraphics();
panel.setBackground(Color.white);
g.setXORMode(panel.getBackground());
g.drawString(text,x,y);
g.dispose();
}
return panel.getSize();
}
74 */
public Dimension getRandomPosition() {
/*
* JFrame.java
*
* Created on 2 octobre 2001, 16:56
*/
import java.awt.event.*;
import javax.swing.*;
import *;
/**
*
* @author genael
* @version
*/
public class ThreadFrame extends JFrame {
getContentPane().add(panel, BorderLayout.CENTER);
startButton.setText("D\u00e9marrer thread");
startButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
startButtonActionPerformed(evt);
}
}
);
southPanel.add(startButton);
closeButton.setText("Fermer");
closeButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt) {
closeButtonActionPerformed(evt);
}
}
);
southPanel.add(closeButton);
getContentPane().add(southPanel, BorderLayout.SOUTH);
}
// Variables declaration
private JPanel panel;
private JPanel southPanel;
private JButton startButton;
private JButton closeButton;
private int threadCount;
}
Code source ThreadFramet.java
E. Groupes de threads
Dans le cas où votre programme contient une grande quantité de threads, il peut être utile de
manipuler ces threads par groupe. Reprenons l'exemple du navigateur internet téléchargeant
des images. Lorsque vous cliquez sur Arrêter , le navigateur doit stopper le téléchargement des
COURS Java – Notions avancées
images. Si chaque image se télécharge par l'intermédiaire d'un thread et que tous , font partie
d'un groupe, nous disposons d'un moyen efficace de les stopper tous.
Un groupe peut posséder des groupes enfants. Le fait d'interrompre les threads du groupe
parent, interromps également les membres des groupes enfants
Il existe un nombre important de methods pour gérer ces groupes. Consultez la doc API Java 2
pour en savoir plus
COURS Java – Notions avancées
F. Synchronisation
F.1. Présentation du problème
Dans de nombreux cas, les threads partagent les mêmes objets et par conséquent, la
modification de ces objets par un thread pourrait avoir des conséquences fâcheuses pour les
autres thread notamment si ceux-ci modifient un objet en même temps.
Java propose un mécanisme de verrouillage des objets par un thread de telle sorte qu'aucun
autre thread ne puisse le modifier aussi. Néanmoins cela ne résoud pas tous les problèmes
puisque les threads peuvent également être interrompu pendant leur travail.
Voici une illustration de ce qui pourrait arriver sur un compte bancaire sans verrouillage des
données :
Thread 1 Thread 2
Tran sfert d e co m p te 1 ve rs V érifie la so m m e d es 2
co m p te 2 de 50 E u ro s co m p tes
D éb it
d e 5 0 E u ros du C om pte 1 C o m p te 2
co m p te 1 500 0
C réd it
d e 5 0 E u ros du 450
co m p te 2
Pendant un certain laps de temps, la somme des 2 comptes sera inexacte !!!
Il faut donc que le Thread 1 soit certain de ne pas être interrompu pendant le transfert.
notify et notifyAll
Donc , si un thread appelle sa méthode wait , il n'a aucun moyen de se débloquer lui-même. Il
doit donc compter sur les autres threads pour appeler la méthode notifyAll ou notify. Si ce n'est
pas le cas, nous sommes en présence d'un verrou mort (deadlock).
Pour éviter ce genre de situation, pensez toujours à appeler régulièrement la méthode notifyAll
ou notify.
La méthode notify donne l'ordre au gestionnaire des threads de débloquer un thread au hasard.
La méthode notifyAll débloque tous les threads qui deviennent par voie de conséquence
exécutables.
Threads exécutables
File d’attente des threads ayant
appelé la m éthode w ait
notifyA ll( )
le s
xéc u ta b
nn ent e
D e v ie
Thread bloqué
Thread exécuté
File d'attente des threads
COURS Java – Notions avancées
Il peut être dangereux d'appeler la méthode notify car vous ne savez pas quel thread sera
débloqué. Il est plus approprié d'employer la méthode notifyAll.
L'endroit le plus approprié pour appeler cette méthode est dans l'objet qui est susceptible de
changer la donne pour les threads mis dans la file d'attente avec wait.
Il faut savoir que le mécanisme de synchronisation ralentit les programmes qui l'utilise. C'est le
prix à payer pour un mécanisme assurant une très bonne intégrité des données.
A p plication
Présentatio n
Session
Tran spo rt
R éseau
Liais on de do nné es
Ph ysiqu e
A.2. Protocoles
Les protocoles de communication réseau peuvent travailler sur des couches différentes et la
plupart d'entre eux sont dépendants des protocoles travaillant sur les niveaux inférieurs. Par
exemple , le protocole FTP10 qui travaille sur la couche Application est dépendant de TCP11 qui
lui, travaille sur la couche Transport.
Si vous connaissez la plupart des protocoles liés au modèle OSI, voici un schéma représentant
les protocoles ainsi que les couches sur lesquelles ils travaillent.
7
OSI : Open System Interconnection : Modèle basé sur une architecture à 7 couches
8
Paquets : Les données à transmettre sont scindées en plusieurs petites unités appelés Paquets
9
Datagrammes : Données envoyées sur le réseau sans aucune certitude sur leur réception sur l'hôte de destination
10
FTP : File Transfer Protocol : Protocole de transfert de fichiers très utilisé sur Internet
11
TCP : Transport Control Protocol : Protocole de transfert contrôlé
COURS Java – Notions avancées
Liais on de do nné es
P P P : P oint to P oint P rotocol
Ph ysiqu e
IN TER N ET
C LIEN T
P orts du serveur
P orts du client SE RVEU R
21
21 80
80 25
25 53
53 …
…
12
Adresse IP : Adresse sur 32 bits (Norme IPv4) utilisée pour communiquer sur un réseau Intranet ou Internet
13
HTML : HyperText Markup Language – Langage utilisé pour les pages internet
COURS Java – Notions avancées
Constructeurs de Socket
protected Socket()
Crée une socket en mode non connecté, avec une version par défaut de
SocketImpl. Utilisable par les classes enfant de Socket.
Socket(InetAddress address, int port)
Crée une connexion vers l'hôte ayant l'adresse et le port donnés en arguments
Socket(InetAddress address, int port, InetAddress localAddr,
int localPort)
Crée une connexion vers l'hôte ayant l'adresse et le port donnés en arguments.
localAddr et localPort paramètre les données sources de la socket
protected Socket(SocketImpl impl)
Crée une socket en mode non connectée avec une version spécifique de
SocketImpl
Socket(String host, int port)
Crée une connexion avec le nom de l'hôte spécifié ainsi que le port. L'appel à cette
méthode sous entend qu'il y a une résolution de nom en adresse IP.
Socket(String host, int port, InetAddress localAddr,
int localPort)
Même chose que la précédente avant en plus , des precisions sur l'adresse locale
et le port
Constructeurs de Socket
Il existe d'autres constructeurs non documenté ici car ils ne s'utiliseront plus dans les versions à
venir du JDK.
Il est souvent plus utile, surtout sur Internet, de lire et d'écrire des caractères sur le réseau.
Pour le faire, il suffit d'utiliser la force de frappe des flux filtrés14 :
Socket s = new Socket(hote, port );
BufferedReader in = new BufferedReader (
new InputStreamReader(s.getInputStream()));
14
Flux filtrés : Voir chapitre sur les flux et les fichiers
COURS Java – Notions avancées
Dans notre exemple , nous obtenons un flux de caractères bufférisé provenant de l'hôte. Il
nous reste à effectuer une boucle de lecture des caractères :
String line;
while ( (line = in.readLine()) != null )
System.out.println(line);
Temps d'attente
Sur un réseau, il y a une ribambelle de raisons pour lesquelles la communication peut échouer.
Une socket qui tente de communiquer avec une autre machine non disponible peut bloquer un
programme indéfiniment. C'est pourquoi une socket peut attendre un certain temps défini par
le programmeur, puis abandonner la connexion si celle-ci ne peut se faire avant le délai imparti.
Ce délai se fixe grâce à la méthode setSoTimeout :
s.setSoTimeout(10000); // Timeout de 10s
Après ce délai, la socket est fermée. Toute opération de lecture ou d'écriture déclenche alors
une interruption de type InterruptedIOException. Par conséquent, il peut être vraiment utile de
lever cette exception au cas où :
try {
Socket s = new Socket(hote, port );
s.setSoTimeout(10000);
BufferedReader in = new BufferedReader (
new InputStreamReader(s.getInputStream()));
String line;
while ( (line = in.readLine()) != null )
System.out.println(line);
} catch (InterruptedIOException ie) {
System.out.println("Délai d'attente dépassé");
}
L'exemple précédent ne résout pas pour autant le problème puisque l'appel au constructeur
peut geler le programme si la connexion n'abouti pas. Il faut déjà posséder un objet de type
Socket avant d'appeler la méthode setSoTimeout.
Pour résoudre ce problème, il vous faudra créer la socket dans un thread15 séparé.
Socket et Thread
Pour illustrer le point qui vient d'être soulevé, voici une classe nommée SocketOpener
permettant d'ouvrir une socket dans un thread séparé et de renvoyer la socket lorsqu'elle est
ouverte et si elle n'a pas atteint la valeur de timeout:
import java.net.*;
import java.io.*;
15
Thread : Voir le chapitre concernant les threads
COURS Java – Notions avancées
if (s==null)
System.out.println("La socket n'a pas pu être ouverte");
else
// Travail avec la socket
Si vous exécutez le programme qui suit avec la commande suivante, vous obtiendrez, si vous
êtes connecté à Internet, l'adresse IP 212.37.208.183 :
java InetAddressTest www.gita.greta.fr
import java.net.*;
import java.io.*;
try {
Une fonctionnalité intéressante de cette classe consiste à obtenir toutes les adresses IP
correspondant au nom DNS fourni. Il s'agit de la méthode statique getAllByName . Voici
l'exemple précédent modifié :
import java.net.*;
import java.io.*;
try {
IP 5 : www.yahoo.com/64.58.76.225
IP 6 : www.yahoo.com/64.58.76.178
IP 7 : www.yahoo.com/64.58.76.227
IP 8 : www.yahoo.com/64.58.76.224
IP 9 : www.yahoo.com/64.58.76.226
IP 10 : www.yahoo.com/64.58.76.223
IP 11 : www.yahoo.com/64.58.76.179
try {
String line;
out.println("quit");
while ( !(line=in.readLine()).toUpperCase().equals("STOP") )
System.out.println(line);
System.out.println("Fermeture de la connexion...");
s.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
ClockClientSocket.java
Ligne 10 : Ouvre une connexion avec l'hôte local sur le port 8189
Ligne 12 : Crée le flux d'entrée de cette connexion comme un flux de caractères
bufferisé.
Ligne 14 : Crée le flux de sortie de cette connexion comme un flux de caractères
Ligne 18 : Envoie la commande quit permettant de mettre fin à la connexion
Ligne 20 : Boucle lisant le flux entrant jusqu'à ce que le serveur renvoie la
commande STOP.
Voici ce que le programme affichera :
Bienvenue sur ClockServer - Version 1.0 - VALET G ©
***************************************************
Voici la date d'aujourd'hui :
COURS Java – Notions avancées
C. Implémenter un serveur
C.1. Types de serveurs
Maintenant que nous avons vu la manière de se connecter à un serveur, nous allons passer aux
choses sérieuses en étudiant ce qui se passe côté serveur. En fait, un serveur est à l'écoute du
client qui se connecte et réagit en fonction des données qu'il reçoit.
Il existe 2 types de serveurs : le serveur capable de gérer un seul client et le serveur multi-
client.
Par exemple , un serveur HTTP16 est à l'écoute des requêtes de plusieurs clients et leur renvoie
les pages au format HTML demandées.
C lient 1
C lient 2
S erveur H TTP
Thread 1
Thread 2
Thread 3
Thread 4
C lient 3
C lient 4
Dans le schéma ci-dessus, chaque connexion vers le client doit s'exécuter dans un threads
différents. Les clients peuvent donc effectuer des requêtes simultanément, le serveur saura
gérer l'envoi et la réception de données sur ces clients.
16
http : HyperText Transfer Protocol
COURS Java – Notions avancées
Lorsque le client est connecté, le dialogue peut commencer entre le client et le serveur :
BufferedReader in = new BufferedReader (
new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(client.getOutputStream());
out et sa méthode print ou println permettra d'envoyer des caractères au client, alors que la
méthode readLine de in permettra une lecture bufferisée des requêtes du client.
Pour écrire au client :
out.println("Résultat de la requête");
out.flush();
Pour écouter le client :
String line = in.readLine();
import java.net.*;
import java.io.*;
import java.util.*;
/**
*
* @author Génael VALET
* @version 1.0 - Oct 2001
*/
public class ServerSocketTest {
try {
ServerSocket s = new ServerSocket(8189);
COURS Java – Notions avancées
while (true) {
Socket client = s.accept();
BufferedReader in = new BufferedReader(
new InputStreamReader( client.getInputStream()));
String line;
boolean fin=false;
while ( (line=in.readLine())!=null && !fin) {
out.println("Echo :" + line);
if (line.trim().toUpperCase().equals("QUIT")) {
fin = true;
out.println("STOP");
}
}
client.close();
}
} catch (SocketException se) {
System.out.println("Interruption de type SocketException");
} catch (Exception e) {
System.out.println(e);
}
}
}
ServerSocketTest.java
Echo :Salut
Tapez QUIT puis Entrée :
Echo :QUIT
STOP
COURS Java – Notions avancées
C:\>
La session telnet se termine et les connexions sont perdues. Le serveur est libre et une autre
connexion client peut se produire.
Pour fermer le serveur, il suffit de fermer la fenêtre d'exécution
/**
*
* @author Génael VALET
* @version 1.0 - Oct 2001
*/
try {
ServerSocket s = new ServerSocket(8189);
while(true) {
ThreadedSocket th = new ThreadedSocket(s.accept());
th.start();
}
} catch (SocketException se) {
System.out.println("Interruption de type SocketException");
} catch (Exception e) {
System.out.println(e);
}
}
}
MultiSocketServer.java
import java.net.*;
import java.io.*;
import java.util.*;
79 /**
80 *
81 * @author Génael VALET
82 * @version 1.0 - Oct 2001
83 */
public class ThreadedSocket extends Thread {
try {
BufferedReader buffer = new BufferedReader(
new InputStreamReader(client.getInputStream()));
PrintWriter writer = new PrintWriter(
client.getOutputStream(),true);
writer.println( "Bienvenue sur le serveur" );
String line;
boolean fin=false;
while ( (line=buffer.readLine())!=null && !fin) {
writer.println("Echo :" + line);
if (line.trim().toUpperCase().equals("QUIT")) {
fin = true;
writer.println("STOP");
}
}
client.close();
} catch (SocketException se) {
System.out.println("Interruption de type SocketException");
} catch (Exception e) {
System.out.println(e);
}
}
}
ThreadedSocket.java
Ligne 17 : Méthode run du thread qui sera appelé par la méthode start()
Lignes 20-23 : Création des flux entrant et sortant de la socket
Ligne 24 : Envoi du message de bienvenue au client
Ligne 28 : Boucle de lecture des informations en provenance du client
Ligne 30 : Si le client renvoie la commande QUIT, la boucle se termine car la
variable fin sera égale à true.
Pour exécuter plusieurs clients, il vous suffit de démarrer plusieurs sessions telnet comme
décrit plus haut et de constater que le serveur répond à tous les clients .
COURS Java – Notions avancées
Méthode openConnection
La classe URL permet aussi, grâce à sa méthode openConnection d'effectuer une connexion vers
l'adresse qu'elle représente.
URL url = new URL ("http://www.gita.greta.fr/index.htm");
URLConnection con = url.openConnection();
Méthode openStream
Cette méthode permet d'ouvrir une connexion et de récupérer un flux d'entrée de données
depuis le serveur correspondant à cette connexion :
InputStream in = url.openStream();
Cette méthode est équivalente à :
InputStream in = url.openConnection().getInputStream();
17
RFC – Request For Comment – Groupe de travail régissant les normes des différents protocoles informatiques
18
URL – Uniform Ressource Locator – Adresse Internet
COURS Java – Notions avancées
setDoInput et setDoOutput
Ces méthodes sont utilisées pour déterminer si vous allez uniquement recevoir des données ou
si vous allez en envoyer. Elles vont fixer les champs booléens doInput et doOutput.
Par défaut, toute nouvelle connexion fixe le champ doInput à la valeur true et celle de doOutput
à false.
Méthode setIfModifiedSince
L'appel à cette méthode va déterminer si il est nécessaire de recharger l'objet souhaité selon
des critères de temps. En effet, le paramètre à transmettre avec la méthode représente le
nombre de millisecondes écoulées depuis le 1er Janvier 1970. Si l'objet n'a pas été modifié
depuis la date représentée par ce paramètre, alors l'objet ne sera pas rechargé.
Méthode setUseCaches
Détermine l'utilisation du cache en fixant le champ booléen useCaches à true pour activer le
cache ou à false pour recharger l'objet quoiqu'il arrive. Cette méthode n'est utile que pour les
applets
Méthode connect
Cette méthode ouvre une socket vers le serveur et demande à celui-ci les informations d'en-
tête de l'objet demandé. Ces informations représentent les propriétés de l'objet comme , la
date de dernière modification, le type de contenu (content type), la taille de l'objet (content
length), le type de codage (content encoding), ou encore la date d'expiration (expiration)
String getContentType()
long getDate()
long getExpiration()
long getLastModified()
Méthode getHeaderFieldKey
Voilà comment obtenir les informations d'en-tête du serveur. Voici la signature de cette
méthode :
String getHeaderFieldKey( int n )
n représente le nième champ d'en-tête. Il n'est pas possible de savoir combien de champs le
serveur contient. Cette méthode renvoie null lorsqu'il n'y pas plus de champs.
Voici un programme permettant d'obtenir ces informations auprès d'un serveur :
import java.net.*;
import java.io.*;
try {
URL url = new URL("http://www.gita.greta.fr");
URLConnection con = url.openConnection();
int n = 1;
String key;
con.connect();
while ((key = con.getHeaderFieldKey(n))!= null) {
String valeur = con.getHeaderField(n++);
System.out.println(key + ":" + valeur);
}
} catch (MalformedURLException mie) {
System.out.println("Url incorrecte");
} catch ( IOException ie) {
System.out.println("Problème d'entrées sorties");
System.out.println(ie);
}
}
}
URLConnectionTest.java
try {
URL url = new URL("http://homewk");
URLConnection con = url.openConnection();
85 BufferedReader in = new BufferedReader(
86 new InputStreamReader(con.getInputStream()));
String line;
while ( (line=in.readLine())!=null)
System.out.println(line);
Méthode POST
La méthode POST réalise la même chose mais l'URL renvoyée est plus simple puisque les
données sont cachées au sein des requêtes http.
Ecrire des données
En Java, nous allons envoyer des données au serveur du GITA par la méthode POST. Le but
étant de connaître le nombre de visiteurs à l'instant sur le site, nous allons effectuer une
requête auprès du serveur suivant :
http://www.gita.greta.fr/getinfo.asp
avec les informations transmises par POST
visit=true
Ce qui signifie que les données de retour devront contenir le nombre de visiteurs présents sur
le site.
Il faut commencer par créer correctement un objet URLConnection puis le paramétrer pour
qu'il accepte un flux sortant. Cela passe donc par la création d'un flux de type PrintWriter
obtenu grâce à la méthode getOutputStream() de la classe URLConnection:
La deuxième étape consiste à écrire les informations devant être transmises par la méthode
POST
out.print("visit=true");
out.close();
Il ne reste plus qu'à lire les données renvoyées par le serveur par le biais d'un flux de caractères
bufferisé et d'une boucle s'arrêtant lorsqu'il n'y a plus de données :
String line;
while ( (line=in.readLine())!=null)
System.out.println(line);
Nous obtenons alors le résultat suivant à l'écran :
Le nombre de visiteurs présents sur le site est de 12
try {
URL url = new URL("http://www.gita.greta.fr/getinfo.asp");
COURS Java – Notions avancées
String line;
while ( (line=in.readLine())!=null)
System.out.println(line);
19
Java DataBase Connectivity
20
Structured Query Language
21
Open DataBase Connectivity
COURS Java – Notions avancées
B. Présentation
B.1. Schéma
Ceci permet, comme nous allons le voir, de s'adapter à tout type d'infrastructure existante.
COURS Java – Notions avancées
Pilote de type I
Ce type de pilote utilise l'interface ODBC qui , dans le monde Windows permet
de se connecter à tout type de base de données.
Les appels de JDBC sont convertis en appels ODBC , ce qui en terme de
performance, n'est pas toujours l'idéal
Java utilise une librairie native écrite en C ce qui exclue de le faire fonctionner au
sein d'une applet
Il est fourni avec le kit Java par l'intermédiaire de la classe
sun.jdbc.odbc.JdbcOdbcDriver
Voici le code nécessaire pour enregistrer ce type de pilote auprès du gestionnaire :
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Pilote de type II
Une partie de ce pilote est écrit en Java et l'autre partie dans le langage
propriétaire natif de la base de données.
Les appels JDBC sont alors convertis en appels vers les API natives de la base de
données
Cela implique que pour accéder à ce type de pilote, il faut installer sur la machine
les API natives
Les appels au code natif exclue d'utiliser ce type de pilote au sein d'une applet
Ces pilotes sont généralement payants et écrits par des sociétés tierces ou par
l'éditeur de la base de données
La portabilité du code n'est plus assurée à cause de la partie langage natif
Pilote de type IV
Pilote 100% Java qui se connecte directement à la base de données sans la
nécessité d'un programme middleware
Les requêtes sont alors directement traduites et envoyés grâce à l'utilisation des
sockets23
Le pilote de type IV est utilisable avec les applets (à condition que l'applet soit
stockée sur le même serveur que la base de données).
22
Programme intermédiaire agissant comme un traducteur entre une application cliente et une application
serveur. C'est un des éléments de l'architecture 3 tiers.
23
Elément de programmation permettant d'effectuer une connexion à un hôte distant via le réseau
COURS Java – Notions avancées
http://java.sun.com/products/jdbc
Sachez que la plupart des éditeurs de bases de données fournissent des pilotes de type III ou IV
, ce qui constitue un gage de performance et de compatibilité avec le langage SQL.
Pour travailler avec la passerelle JDBC/ODBC , pas besoin de pilote, il est intégré dans le kit Java
de Sun.
La plupart du temps, le pilote se présente sous la forme d'un fichier JAR24. Ce fichier doit être
positionné dans un répertoire liste dans la variable CLASSPATH25. Le nom du package fourni
correspond toujours à un nom faisant partie d'un espace de noms, comme on peut les trouver
sur Internet :
com.mysql.jdbc
Ci-dessus, un exemple de nom de package pour le driver de la base de données MySql que vous
pouvez vous procurer gratuitement à l'adresse :
http://www.mysql.com/products/connector-j
Inutile d'importer le package contenant le pilote. Les bonnes classes seront utilisées lors de
l'enregistrement du pilote par le gestionnaire de pilotes.
24
Java ARchive
25
Classpath : Variable d'environnement contenant la liste des répertoires concernés par Java susceptible de
contenir des packages ou des archives utiles pour la compilation
COURS Java – Notions avancées
Voici le même exemple pour travailler avec une base de données Access via l'interface OBDC :
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
L'exemple ci-dessus permet de travailler avec n'importe qu'elle base de données (Et pas Access
seulement) à partir du moment où l'on possède le pilote ODBC approprié. L'utilisation du pont
JDBC/ODBC ne fait que reporter le problème du pilote vers ODBC.
Le pont JDBC/OBDC suppose que la base et ODBC sont installés sur la même machine locale. C'est
pourquoi, dans l'URL proposée ci-dessus, ne figure pas le nom d'un serveur distant mais le nom
de la source de données locale.
26
Uniform Ressource Locator
COURS Java – Notions avancées
Méthode getConnection
Rappelons-nous que le gestionnaire de pilote (Driver Manager) est chargé de nous fournir les
connexions par l'intermédiaire d'un objet, instance de la classe Connection.
Connection c;
c = DriverManager.getConnection(url,"username","password");
Lors de l'appel à getConnection , le gestionnaire de pilotes essaie tous les pilotes qui ont été
enregistrés par l'appel à Class.forName(…) jusqu'à ce qu'il obtienne une connexion vers la base
désignée par l'URL. Cela signifie que si plusieurs pilotes enregistrés permettent de se connecter à
la base, c'est le 1er pilote enregistré qui aura gain de cause.
Connection c;
c = DriverManager.getConnection(url,"username","password");
Statement st = c.createStatement();
A ce stade, le Statement est initialisé mais aucune requête vers la BD n'est effectuée.
Connection c;
c = DriverManager.getConnection(url,"username","password");
Statement st = c.createStatement();
27
Procédures complexes programmées par l'administrateur de la base de données pour faciliter la manipulation
de données par l'utilisateur. Ces procédures sont comme des fonctions appelées avec , si nécessaire, des
paramètres d'exécution définis par l'utilisateur.
COURS Java – Notions avancées
Le code suivant permet de lire un nom et le prénom dans une base de données de clients :
String url = "jdbc:mysql://bd.diderot.org:3306/diderot";
Connection c;
c = DriverManager.getConnection(url,"username","password");
Statement st = c.createStatement();
Donc, pour éviter de bloquer votre programme Java dans le cas où une erreur se produit, vous
aurez recours à l'utilisation des exceptions, d'autant plus que cela vous est imposé de la part du
compilateur. En effet, toutes les opérations relatives aux bases de données sont susceptibles de
renvoyer une exception de type SQLException.
Vos programmes devront donc être conçus pour prévoir les actions à mener au cas où les
opérations vers les bases de données se déroulent mal.
Voici un exemple complet de programme permettant de se connecter à une base de données
avec la gestion des exceptions :
try { Se produit si le
Class.forName("com.mysql.jdbc.Driver"); pilote désigné n'est
pas présent dans le
} catch (ClassNotFoundException ex) {
System.out.println("Pilote JDBC non enregistré");système Java
}
try {
Connection c;
c = DriverManager.getConnection(url,"username","password");
Statement st = c.createStatement();
rs.next() ;
Voici un exemple :
Connection c;
c = DriverManager.getConnection(url,"username","password");
Statement st = c.createStatement(ResultSet.FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
Statement st = c.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
Voici l'exemple d'un ResultSet non modifiable, de type sensible aux modifications faîtes par
ailleurs et que l'on peut parcourir dans tous les sens :
Connection c;
c = DriverManager.getConnection(url,"username","password");
Statement st = c.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_READ_ONLY);
Statement st = c.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ATTENTION : Certaines bases de données sont incapables de fournir des ResultSet avec de
telles caractéristiques. En cas de doute, il peut-être très utile de manipuler les méta-
données (Voir plus loin dans ce chap.) et notamment d'appeler les méthodes
supportsResultSetType et supportsResultSetConcurrency de la classe DatabaseMetaData.
COURS Java – Notions avancées
F. Parcourir un ResultSet
F.1. Les méthodes
Il existe plusieurs façons de parcourir un jeu d'enregistrements. Voici un tableau listant les
différentes méthodes permettant de naviguer dans un jeu d’enregistrements :
Method Summary
boolean absolute(int row)
Déplace le curseur à la ligne passée en paramètre
void afterLast()
Déplace le curseur à la fin de ce ResultSet , juste après la
dernière ligne.
void beforeFirst()
Déplace le curseur à la fin de ce c avant la première ligne
boolean first()
Déplace le curseur sur la première ligne
boolean isAfterLast()
Renvoie true si le curseur se situe après la dernière ligne.
boolean isBeforeFirst()
Renvoie true si le curseur se situe avant la première ligne.
boolean isFirst()
Renvoie true si le curseur se situe sur la première ligne
boolean isLast()
Renvoie true si le curseur se situe sur la dernière ligne
boolean last()
Déplace le curseur sur la dernière ligne
void moveToCurrentRow()
Déplace le curseur à la dernière position mémorisée du curseur. Il
s’agit habituellement de la ligne courante
void moveToInsertRow()
Déplace le curseur à la position d’insertion d’un nouvel
enregistrement
boolean next()
Déplace le curseur à la position suivante. Renvoie false si aucune
ligne ne suit la ligne courante
boolean previous()
Déplace le curseur à la position précédente. Renvoie false si
aucune ligne ne précède la ligne courante
boolean relative(int rows)
Déplace le curseur d’un nombre de lignes fourni en paramètre. Ce
COURS Java – Notions avancées
F.2. Exemple
Voici un exemple de programme capable de parcourir un objet ResultSet et d’afficher à l’écran
le champ nom d’une table nommée Clients :
try {
Class.forName("com.mysql.jdbc.Driver");
try {
Connection c;
c = DriverManager.getConnection(url,"username","password");
Statement st = c.createStatement();
Avant de modifier un ResultSet, il faut s’assurer que ce dernier est bien du type
CONCUR_UPDATABLE (Voir Caractéristiques d’un ResultSet).
G.1. Insérer
Avant d’insérer une ligne, il faut faire appel à la méthode moveToInsertRow(). Cette opération
revient à placer le curseur sur une ligne spéciale utilisée pour l’insertion uniquement.
rs.moveToInsertRow();
Ensuite, il faut mettre à jour les champs de la nouvelle ligne grâce aux méthodes updateXXX
ou XXX représente le type champ à mettre à jour :
rs.updateString(“nom”,”VALET”); // Met à jour le champ nom
COURS Java – Notions avancées
L’appel à la méthode insertRow() est équivalent à une requête SQL de type INSERT. Néanmoins,
il est plus judicieux d’utiliser les méthodes de ResultSet plutôt que les requêtes SQL. Ceci est
valable pour la version 2 de JDBC (Très utilisée aujourd’hui)
G.2. Modifier
Pour modifier une ligne, il suffit de positionner le curseur sur cette ligne et de faire des appels
successifs aux méthodes updateXXX.
Pour valider les changements dans la base de données, il convient d’utiliser la méthode
updateRow().
rs.updateString("nom","DUPONT");
rs.updateInt("age",35);
rs.updateRow();
L’avantage de ces objets est qu’ils peuvent être exécutés avec des paramètres différents à
chaque exécution. Une requête pourra être executée plusieurs fois avec un seul objet
PreparedStatement.
Pour changer les frais de port pour tous les clients habitant la ville de Lyon, il suffit de réutiliser
la requête pre-compilée :
updatePort.setDouble(1,7.5);
updatePort.setString(2, "Lyon");
updatePort.executeUpdate();
I. Les méta-données
I.1. Introduction
Dans les pages précédentes , nous sommes partis du constat que nous connaissions
parfaitement les types et les noms des champs présents dans la base de données. Parfois, il
peut-être utile d’avoir accès à certaines informations sur la structure et les types de données
d’une base.
Les méta-données contiennent donc des informations sur la structure de la base de données
(Les tables, les champs, …)
Toutes les bases de données n’autorisent pas l’utilisation des méta-données
I.2. DatabaseMetaData
Il s’agit d’une classe vous permettant d’obtenir un maximum d’informations sur la base de
données elle-même. Ces informations explorent toute la complexité des bases de données et
selon le type de base, tout ou partie de ces informations peuvent ne pas être disponibles.
Voici un programme qui extrait quelques informations à propos d’une base ACCESS en passant
par le pont JDBC/ODBC. Le programme utilise la classe Properties , qu’il convient de connaître
avant de se plonger dans le programme :
import java.sql.*;
import java.util.*;
// Etablissement de la connexion
Récupération d’un Connection c;
objet de type String url = "jdbc:odbc:cours3java";
DatabaseMetaData
nommé md c=DriverManager.getConnection(url);
md.getSQLKeywords() );
prop.setProperty("Supporte les procedures stockees",
String.valueOf(md.supportsStoredProcedures()));
I.3. ResultSetMetaData
Voyons maintenant comment obtenir des informations plus détaillées sur les objets ResutSet et
les lignes et colonnes qu’il contient. En effet, il peut-être très intéressant de connaître la taille
ou encore le type de données d’un champ avant d’y insérer des données.
Voici une liste des méthodes pouvant être utilisées pour obtenir des informations
Voici un extrait de programme permettant de vérifier la taille maximale d’une chaîne dans un
champ et de tronquer la chaîne à insérer en cas de dépassement :
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2");
if (tailleMax<maChaine.size()) Tronquage de la
maChaine = machaine.substring(1,tailleMax); chaîne si
dépassement
COURS Java – Notions avancées
rs.updateString("champ",maChaine);
rs.updateRow(); Mise à jour du champ
Mise à jour de la base
J. Transactions avec JDBC
J.1. Introduction
Lorsque l’on modifie les données d’une base, il est vital de maintenir une certaine cohérence
dans les données. Imaginons une base de données contenant toutes les informations
concernant les vols d’une compagnie aérienne. Pour supprimer un passager d’un vol en
particulier, il faut supprimer la ligne le concernant grâce à une requête de type DELETE. Il faut
également mettre à jour le nombre de sièges libres sur ce vol. Nous avons là deux opérations à
mener. Que se passera-t-il si la première opération qui consiste à supprimer le passager se
déroule bien mais que la mise à jour du nombre de sièges libres ne se fait pas ? Il y aura des
données corrompues dans la base.
Les transactions peuvent résoudre ce problème. Elles consistent à englober plusieurs
opérations dans un même sous-ensemble et de considérer que la transaction a abouti lorsque
toutes les opérations ont réussi. Si une des opérations échoue, alors, toutes les autres sont
également annulées.
ResultSet rs = volStmt.executeQuery(strSql);
int nbPassagers = rs.getInt(“nbPassagers”); Requête SQL pour
récupérer le vol à
rs.updateInt(“nbPassagers”,--nbPassager);
rs.updateRow(); modifier
Validation de
con.commit(); la Mise à jour du
transaction nombre de passagers
COURS Java – Notions avancées
con.setAutoCommit(true);
Activation des
J.3. Annuler une transaction
transactions
automatiques
Afin d’être absolument pour
sûr qu’aucune modifications de données n’a pu être validée, il est
cette connexion
préférable d’annuler une transaction lorsqu’une exception de type SQLException est générée.
Pour annuler une transaction , il suffit d’appeler la méthode roollback() de Connection. Il est
préférable d’appeler la méthode rollback() dans le cas où une des opérations vers la base de
données a provoqué une exception de type SQLException :
Notez que les méthodes rollback() et commit() sont également susceptibles de provoquer une
exception. Pour une fiabilité maximum, certains développeurs insèrent l’appel à rollback() à
l’intérieur d’un bloc try…catch . L’imbrication de bloc try…catch étant accepté en Java, il devient
alors possible d’empêcher une perte des données au cas où la méthode rollback() échouerait.
A H
accept, 39 HTML, 39
activeCount Voir Threads HTTP, 33, 39, 44
ANSI, 4 HttpURLConnection, 45
B I
BufferedInputStream, 7 InetAddress, 34, 36
BufferedReader, 12, 34, 39 InputStream, 4
read, 5
C
InputStreamReader, 8, 12, 34, 40
CallableStatement, 56 insertRow, 63
catch, 10 interrupt, 20
Class, 54 InterruptedIOException, 35
closeEntry, 12 IOException, 11, 36
commit, 69, 70 isAlive, 20
CONCUR_UPDATABLE, 61
J
connect, 45
coopératif Voir Multitâche java.sql, 53
createStatement, 60, 61 java.util.zip, 12
join, 35
D
L
DatagramPacket, 32
DatagramSocket, 32 line.separator, 10
DataInputStream, 6
M
read, 6
readBoolean, 6 MAX_PRIORITY, 21
readByte, 6 MIN_PRIORITY, 21
readChar, 6 moveToCurrentRow, 64
readDouble, 6 moveToInsertRow, 63
DriverManager, 51 Multitâche, 16
coopératif, 16
E
préemptif, 16
executeQuery, 56, 59
N
executeUpdate, 65
NORMAL_PRIORITY, 21
F
notify, 29
File, 6 notifyAll, 29
FileInputStream, 6
O
FileNotFoundException, 11
FileReader, 9 openConnection, 44
FileWriter, 9 openSocket, 36
forName, 54 openStream, 44
FORWARD_ONLY, 60 OSI, 31
FTP, 31, 33, 44 OutputStream, 4
write, 5
G
P
GET, 47
getAllByName, 37 passerelle JDBC/ODBC, 53
getBytes, 36 POP3, 32
POST, 47
getConnection, 55 préemptif, 16
getHeaderFieldKey, 46 PreparedStatement, 55, 65
getInputStream, 34, 47 PrintStream, 4
getNextEntry, 12 PrintWriter, 9, 40
getOutputStream, 34 processus Voir Threads
getProperty, 10 Properties
GZIPInputStream, 4 setProperty, 66
COURS Java – Notions avancées
R Writer, 4, 8
read Voir InputStream Z
Reader, 4, 8
ZipEntry, 12
ResultSet, 62, 68
ZipInputStream, 7, 12
ResultSetMetaData, 67, 68
ZIPInputStream, 4
RFC, 44
rollback, 70
Runnable, 17, 18, 35
S
Server, 32
ServerSocket, 32, 39, 42
setAutoCommit, 69, 70
setDoInput, 45
setDoOutput, 45
setIfModifiedSince, 45
setSoTimeout, 35
setUseCaches, 45
sleep, 18, 19
SMTP, 32
Socket, 33
sockets, 33
SQLException, 70
Statement, 55, 56, 61
supportsResultSetConcurrency, 61
supportsResultSetType, 61
suspend, 19
synchronised, 28
System, 9
T
TCP, 31
telnet, 41
thread, 17
Thread, 16, 17
ThreadGroup, 27
Threads
activeCount, 27
processus, 16
Transactions, 70
TRANSACTION_READ_COMMITTED, 70
TRANSACTION_READ_UNCOMMITED, 70
TRANSACTION_REPEATABLE_READ, 70
TRANSACTION_SERIALIZABLE, 70
try, 10
TYPE_SCROLL_INSENSITIVE, 60
TYPE_SCROLL_SENSITIVE, 60, 61
U
UDP, 31
UNICODE, 8
updateRow, 68
updateString, 68
URL, 54
URLConnection, 32, 45
URLEncoder, 32
user.dir, 11
W
wait, 19, 29
COURS Java – Notions avancées Version 2.4 - Mai 2003