Vous êtes sur la page 1sur 34

JDBC

1
Connexion aux bases de données
___________________________
• Rappels
• API JDBC
• Pilotes JDBC
• Connexion
• ResultSet
• requêtes interprétées
• requêtes préparées
2
Modélisation des données
• Création d'un schéma entités/associations
• Entités :
– identifiables ( notion de clé)
– pertinente pour l'application
– caractérisées par des propriétés (attributs)
• Représentation graphique
– OMT, Merise, UML

3
Schéma relationnel
schéma entités/associations schéma relationnel

- tables A et B
A B - la clé de A devient un attribut de B
( clé étrangère)

- tables A et B
- table AB pour l'association
A B ( avec clé=(clé A,clé B)
- attribut de l'association = attribut de la
attr table AB

4
Mysql
Types mysql :
CHAR(n) chaîne de longueur n
INTEGER entier
VARCHAR(n) chaîne de longueur <=n
DECIMAL(m,n) m= longueur partie entière, n=lg partie décimale
DATE jour, mois, an
TIME heure, minutes et secondes
DATETIME date et horaire
TEXT texte de longueur quelconque
Expression des contraintes
DEFAULT val val = valeur par défaut
NOT NULL valeur obligatoire
Clés
PRIMARY KEY( num) l'attribut num est la clé primaire
FOREIGN KEY(idad) REFERENCES Personne
la clé étrangère idad référence la clé primaire de la table Personne
5
Correspondances des types de
données SQL/Java
Type SQL Type Java Méthode getter
CHAR VARCHAR String getString()
INTEGER int getInt()
TINYINT byte getByte()
SMALLINT short getShort()
BIGINT long getLong()
BIT boolean getBoolean()
REAL float getFloat()
FLOAT DOUBLE double getDouble()
NUMERIC DECIMAL java.math.BigDecimal getBigDecimal()
DATE java.sql.Date getDate()
TIME java.sql.Time getTime()
TIMESTAMP java.sql.TimeStamp getTimeStamp()

6
SQL
• Sélection
SELECT attr, ... FROM table, ... WHERE condition
où condition est une expression sur les attributs des tables du FROM
les opérateurs applicables sont
– opérateurs arithmétiques : +,*,-, ...
– opérateurs relationnels : <,>,>=,... ,!=
– opérateurs logiques : AND, NOT, OR
– BETWEEN, IN, LIKE
caractères joker
– '_' remplace n'importe quel caractère
– '%' remplace n'importe quelle chaîne de caractères
• Destruction
DELETE FROM table WHERE condition
• Modification
UPDATE table SET attr1=val1,Ai=vali,... WHERE condition
7
Introduction à JDBC
Pour les applications web utilisant une ou plusieurs bases de
données, les servlets et l'API JDBC offrent une solution :

– efficace, la connexion est maintenue durant tout le


cycle de vie de la servlet et non à chaque invocation

– flexible, l'accès à une base de données dépend peu de


son fournisseur. Il est facile de porter une application
web vers une base de données d'un autre fournisseur

8
Principe de fonctionnement de
JDBC
Permet à un programme Java d'interagir
• localement ou à distance
• avec une base de données relationnelle
Fonctionne selon un principe client/serveur
• client = le programme Java
• serveur = la base de données
Principe
• le programme Java ouvre une connexion
• il envoie des requêtes SQL
• il récupère les résultats
• ...
• il ferme la connexion

9
Architecture 3 tiers

couche couche couche


présentation métier d'accès
utilisateur interface (domaine) aux BD
web données

les trois couches sont rendues indépendantes grâce à l'utilisation


d'interfaces Java

10
API JDBC
l'API JDBC se trouve dans le paquetage java.sql

l'API JDBC est constituée d'un ensemble d'interfaces pour interagir avec
des bases de données

l'API JDBC ne fournit donc aucune implémentation des comportements


spécifiés par les interfaces

l'API JDBC permet d'exécuter des instructions SQL et de récupérer les


résultats

La version la plus récente de l'API est la version 3.0

11
Pilotes JDBC (1/2)
• Le pilote JDBC a pour rôle de permettre l'accès à un système de bases
de données particulier. Il gère le détail des communications avec un
type de SGBD

• A une API JDBC correspond plusieurs implémentations selon les


fournisseurs (un type de driver par SGBD Oracle, Sybase, Access, ...).
Il en existe pour la plupart des SGBD relationnels

• Le pilote implémente l'interface java.sql.Driver

• Il existe un driver générique JDBC-ODBC pour toutes les données


accessibles par ODBC
- SGBD : MS Access, SQL Server, Oracle, dBase, ...
- tableurs : Excel, ...
- tout autre application conforme ODBC 12
Pilotes JDBC (2/2)
4 catégories de pilotes JDBC :
– les pilotes qui connectent des programmes java à des sources de
données ODBC (Open DataBase Connectivity).
Le pont JDBC-ODBC de Sun (sun.jdbc.odbc.JdbcOdbcDriver) est
inclut dans le jdk (accès local seulement) => un driver ODBC
installé sur le client.
accès local uniquement. Utilisé en développement

– les pilotes partiellement écrits en Java qui utilisent des librairies


natives (C/C++) pour accéder aux SGBD.

– les pilotes JDBC écrits en Java qui communiquent localement ou à


distance avec le SGBD selon un protocole générique

– les pilotes pur Java qui utilisent un protocole spécifique au SGBD


13
Gestionnaire de pilotes
DriverManager

• DriverManager est une classe, gestionnaire de tous les


drivers chargés par un programme Java

• Chaque programme Java charge le (ou les) drivers dont il a


besoin

• L'enregistrement des pilotes est automatique

14
Connexion à une base de données
1. Disposer de l'URL d'un pilote pour le SGBD
com:mysql:jdbc:Driver
Sun:jdbc:odbc:JdbcOdbcDriver
2. Charger le pilote
Class.forName("com:mysql:jdbc:Driver");
// création d'une instance du pilote
// enregistrement automatique auprès du
// DriverManager
3. Etablir l'URL (protocole) de la base
String dbUrl="jdbc:mysql://localhost:3306/maBD";
4. Ouvrir la connexion : le DriverManager choisit le pilote approprié à cette
URL parmi l'ensemble des pilotes disponibles.
Connection dbcon =
DriverManager.getConnection(dbUrl,user,password); 15
Code de connexion : exemple
(1/2)
try {
//Déclaration du driver :
Class.forName("com.mysql.jdbc.Driver");
//Url de connexion
String dbUrl="jdbc:mysql://localhost:3306/laboBD";
//Profil/mot de passe
String user = "root";
String password = "19AB5";
//connexion à la base
dbcon =
DriverManager.getConnection(dbUrl,user,password);
}

16
Code de connexion : exemple
(2/2)
catch( ClassNotFounDException e ){
// erreur de chargement du pilote
}
catch( SQLException e ){
// erreur d'obtention de la connexion
}
finally{
// fermeture de la connexion pour libérer
// les ressources de la BD
try{
if (dbcon!=null) dbcon.close();
}
catch(SQLException e){...}
}
17
3 types de requêtes
interface
Statement
requêtes interprétées à
chaque exécution

interface
PreparedStatement
requêtes
précompilées

interface
CallableStatement
requêtes stockées
dans la base18
L'interface ResultSet
Un objet de type ResultSet est une table représentant le résultat d'une
requête à une base de données

Le nombre de lignes du tableau peut être nul.

Les données de la table sont accessibles ligne par ligne grâce à un curseur

Un resultSet gère un curseur sur la ligne courante de la table des


données satisfaisant aux conditions de la requête.

19
Exécution d'une requête SQL de
type Statement (1/2)
• Le type de résultat obtenu dépend de la manière dont on souhaite
manipuler le ResultSet
• 3 manières :
TYPE_FORWARD_ONLY ( le curseur se déplace uniquement vers l'avant )
TYPE_SCROLL_INSENSITIVE ( le curseur se déplace en avant et en
arrière mais les changements faits par d'autres ne sont pas reflétés dans le
ResultSet )
TYPE_SCROLL_SENSITIVE ( le curseur se déplace en avant et en arrière
mais sensible aux changements faits par d'autres)
• Créer un objet de la classe java.sql.Statement
Statement stmt = dbcon.createStatement(
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_READ_ONLY);
// indique que le ResultSet est scrollable et non
// modifiable. ResultSet.CONCUR_UPDATABLE indique
// qu'un seul utilisateur à la fois peut modifier20
// la donnée
Exécution d'une requête SQL de
type Statement (2/2)
• Par défaut, le ResultSet n'est ni scrollable, ni modifiable
Statement stmt = dbcon.createStatement();

• Construire la requête SQL


Soit la table personne(nom,prenom,age)
String reqSQL = "select * from personne";

• Exécuter la requête
ResultSet rs = stmt.executeQuery( reqSQL );

21
Exploiter les résultats d'une
requête (1/5)
A la création du ResultSet,le curseur est placé avant la première ligne.

Pour le déplacer, on dispose des méthodes :

• next() déplacement d'une ligne en avant


• previous() déplacement d'une ligne en arrière
• first() déplacement vers la première ligne
• last() déplacement vers la dernière ligne
• beforeFirst() déplacement avant la première ligne.
Si le ResultSet est vide, cela n'a aucun effet.
• afterLast() déplacement après la dernière ligne.
Si le ResultSet est vide, cela n'a aucun effet.
• relative(int i) déplace de i lignes par rapport à la position courante
• absolute(int i) déplace le curseur vers la i-ème ligne 22
Exploiter les résultats d'une
requête (2/5)
• Déplacement absolu absolute( int i)
i>0 déplacement vers la ligne numéro i
rs.absolute(1) => déplacement vers la ligne 1
i<0 déplacement à partir de la fin
rs.absolute(-1) => déplacement sur la dernière ligne
rs.absolute(-3)=> si 30 lignes, déplacement vers ligne 28
• Déplacement relatif relative( int i)
On spécifie le nombre de déplacements à partir de la ligne courante
i>0 => déplacements en avant
i<0 => déplacements en arrière

rs.absolute(4); // curseur sur la 4ème ligne


rs.relative(-3); // curseur sur la première ligne
rs.relative(2); // curseur sur la 3ème ligne

23
Exploiter les résultats d'une
requête (3/5)
• On récupère le contenu d'une ligne du ResultSet colonne par
colonne
• Les méthodes d'accès sont construites sur le modèle : getXXX (XXX
étant un type primitif ou String)
• La colonne est spécifiée soit par son nom, soit par son numéro (la
première colonne est numérotée 1)
- par son nom
String getString(String nomAttribut)
float getFloat(String nomAttribut)
- par le numéro de la colonne qui lui correspond
String getString(int indexColonne)
float getFloat(int indexColonne)
idem pour les int, double, long, boolean, Object
24
Exploiter les résultats d'une
requête (4/5)
• Pour obtenir le n° de la ligne courante
int getRow()

rs.absolute(5);
int i = rs.getRow(); // i=5

• Pour tester la position dans le Resultset


isFirst, isLast, isBeforeFirst, isAfterLast.

if (rs.isAfterLast() == false) {
rs.afterLast(); }

25
Exploiter les résultats d'une
requête (4/5)

String reqSQL = "select * from personne";


ResultSet rs = stmt.executeQuery( reqSQL );
while (rs.next()){
String prenom = rs.getString("prenom");
int age = rs.getInt("age");
}

26
Mises à jour de table (1/2)
Il est préférable que le ResultSet soit scrollable lors d'une
mise à jour
Statement stmt = con.createStatement(
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);

Pour mettre à jour, 2 méthodes:


updateXXX avec 2 paramètres (nom et valeur de la colonne)
updateRow() rendre effective la mise à jour

27
Mises à jour de table (2/2)
Nom Prénom Age
Meyer René 54->37
Legrand Léa 18
Dupont Marcel->Robert 43

String reqSQL = "select * from personne";


ResultSet rs = stmt.executeQuery( reqSQL );
rs.next();
rs.updateInt("Age",37);
rs.last();
rs.updateString("Prénom","Robert");
rs.updateRow();
28
L'interface
ResultSetMetaData
Permet d'obtenir la description du contenu du ResultSet
ResultSetMetaData metaData = rs.getMetaData();

A partir de cette information, obtenir le nombre de colonnes du résultat


int nbCols = metaData.getColumnCount();

Obtenir le nom de la colonne connaissant son indice (à partir de 1)


String nomCol = metaData.getColumnName( int i );

29
Exemple
ResultSet rs = stmt.executeQuery( "SELECT * FROM personne" );
StringBuffer resultat = new StringBuffer();
ResultSetMetaData metaData = rs.getMetaData();
int nbCols = metaData.getColumnCount();
for ( int i=1;i<=nbCols;i++ )
resultats.append( metaData.getColumnName( i )+"\t" );
resultats.append( "\n" );
while ( rs.next() ){
for ( int i=1;i<=nbCols;i++ )
// pour simplifier, chaque donnée est du type Object
// sinon le type de la valeur est obtenu par getColumnType
resultats.append( rs.getObject( i )+"\t" );
resultats.append( "\n" );
}

30
Requêtes préparées
• L'exécution de chaque requête à une BD nécessite 4 étapes :
– analyse
– compilation
– optimisation
– exécution
• Pour des requêtes identiques, les 3 premières étapes n'ont pas à être
effectuées de nouveau.
• Avec la notion de requête préparée, les 3 premières étapes ne sont
effectuées qu'une seule fois.
• JDBC propose l'interface PreparedStatement qui dérive de
l'interface Statement pour modéliser cette notion.

31
Exécution d'une requête SQL de
type PreparedStatement
Avec l'interface Statement, on écrivait :
Statement smt = dbcon.createStatement();
ResultSet rs = smt.executeQuery("SELECT * FROM personne" );

Avec l'interface PreparedStatement, on écrit :


PreparedStatement pSmt =
dbcon.prepareStatement("SELECT * FROM personne" );
ResultSet rs = pSmt.executeQuery();

• On voit que la requête est préparée à l'avance et n'est donc pas transmise en
argument au moment de l'exécution ( executeQuery()).

32
Exécution d'une requête SQL de
type PreparedStatement
Pour préparer des requêtes paramétrées de la forme :
SELECT nom FROM Personnes WHERE age > ? AND adresse = ?
On utilise les PreparedStatement avec les méthodes
setType(numéroDeLArgument, valeur)
Type représente le type de l'argument
numéroDeLArgument représente le numéros de l'argument (commençant à 1
dans l'ordre d'apparition dans la requête).
valeur représente la valeur qui lui est associée
Exemple :
PreparedStatement pSmt = dbcon.prepareStatement
("SELECT nom FROM Personne WHERE age > ? AND prenom=?" );
pSmt .setInt(1, 22);
pSmt .setString(2, "Adrien");
ResultSet rs = pSmt.executeQuery(); 33
Exécution d'une requête SQL de
type PreparedStatement
PreparedStatement psmt = dbcon.prepareStatement(
"update personne set nom = ? where prenom like ?");
psmt.setString(1, "Bauer");
psmt.setString(2, "René");
int i = psmt.executeUpdate():

On a changé en Bauer le nom de la personne dont le prénom est René


La valeur retournée par executeUpdate() est le nombre de lignes mises à jour

34