Bases de données avancées

publicité
Introduction à JDBC
Bases de données avancées
JDBC
Java DataBase Connectivity
API java adaptée à la connexion aux bases de données
relationnelles (SGBDR)
Ensemble de classes et d'interfaces permettant l'utilisation sur le
réseau d'un ou plusieurs SGBDR à partir d'un programme java
Objectifs
Permettre aux développeurs d'écrire un code indépendant de la
base de données et du moyen de connexion utilisé
Simple à mettre en oeuvre
Indépendant de la SGBD cible
Supportant les fonctionnalités du langage SQL
Avantages de JDBC
Portabilité sur de nombreux OS
Portabilité sur de nombreuses SGBDR (Oracle, MySQL, Access,
SyBase)
Robuste et sécurisé
Uniformité du langage de description des applications et des
accès aux bases de données
Liberté totale vis-à-vis des constructeurs
L’API JDBC
Fourni par le package java.sql
Supporte le standard SQL2 Entry Level
8 interfaces définissant les objets nécessaires à :
✓ La connexion à une base éloignée
✓ La création et l'exécution de requêtes SQL
Principes de fonctionnement
Chaque base de données utilise un pilote (driver) qui lui est
propre et qui permet de convertir les requêtes JDBC dans le
langage natif du SGBDR
Ces drivers existent pour tous les principaux constructeurs de
SGBDR
Oracle
Application
JDBC
MySql
Access
Modèle à deux couches
Couche externe
✓ Couche utile et visible pour développer des applications java
utilisant l'API JDBC
✓ Représentée par le package java.sql
Couche interne
✓ Destinée à faciliter l'implémentation de drivers pour des bases
de données
✓ Représentant une interface entre les accès de bas niveau et la
partie applicative
Modèles de connexion
Modèle 2-tiers : 2 entités interviennent
✓ l'application
✓ le SGBDR
Modèle 3-tiers : 3 entités interviennent
✓ l'application
✓ un serveur (MiddleWare) installé sur le réseau
✓ le SGBDR
Modèle 2-tiers
Principe
✓l'application courante utilise JDBC pour parler directement avec
le SGBDR qui gère la base de données
Avantages
✓Simple à mettre en oeuvre
✓bon choix pour les applications clientes peu évoluées, a livrer
rapidement
Inconvénients
✓Dépendance forte entre le client et la structure du SGBDR
✓Tout le traitement est du coté client.
Architecture 2-tiers
Serveur
Client
SGBD
Application
JDBC
BD
Modèle 3-tiers
Principes
✓ Le serveur MiddleWare est l'interlocuteur direct du code Java
client
✓ C'est lui qui échange des données avec le SGBDR
✓ Pas nécessairement écrit en java
Avantages
✓ Ajoute un niveau de sécurité
✓ Échanges avec le client grâce à Corba, RMI
Inconvénients
✓ Plus lourd à gérer
Architecture 3-tiers
Middleware
Client
Serveur
SGBD
Application
JDBC
BD
Mettre en oeuvre JDBC
Principes
1. Importer le package java.sql
2. Enregistrer le driver JDBC
3. Établir la connexion à la base de données
4. Créer une zone de description de requêtes
5. Exécuter la requête
6. Traiter les données retournées
7. Fermer les différents espaces
Enregistrer le pilote JDBC
Dépend du type de SGBDR sur lequel on veut se connecter
Charger la classe
Class.forName("com.mysql.jdbc.Driver").newInstance();
Il existe des exceptions relatives à cette instruction, on les lèvera
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
catch(Exception e) {
System.out.println("Erreur : " + e.getMessage());
}
}
Se connecter à la BD
Accès à la base via une URL de la forme
jdbc:<sous-protocole>:<nom-BD>;param=valeur,...
✓ Spécifie l'utilisation de JDBC
✓ Spécifie le driver ou le type de SGBDR
✓ Spécifie l'identification de la base locale ou distante
Exemples
String url = "jdbc:odbc:maBase";
String url = "jdbc:msql://leo.inria.fr:1114:maBase";
String url = "jdbc:mysql://localhost:3306/test";
Se connecter... suite
Méthode getConnection() de DriverManager
3 arguments de type String
✓ l'URL de la base de données
✓ le nom de l'utilisateur (optionnel)
✓ son mot de passe (optionnel)
Retourne : une instance de la classe Connection
Connexion c = DriverManager.getConnection(url,user,passwd);
Exceptions à lever de la classe SQLException
Créer une zone de description
Avant de pouvoir exécuter des requêtes SQL, il faut créer une
zone de description de requêtes (classe Statement)
L'objet Statement possède les méthodes nécessaires pour
réaliser des requêtes
Il existe 3 types de Statement
✓ Statement : Requêtes simples
✓ PreparedStatement : requêtes dynamiques précompilées
✓ CallableStatement : procédures stockées
Créer une zone de description
À partir de l'instance de l'objet Connection précédemment créé, on
récupère le Statement associé
Statement st = c.createStatement();
PreparedStatement pst = c.createPreparedStatement();
CallableStatement cst = c.prepareCall();
Éxecution d’une requête
3 types de requêtes
✓executeQuery() pour les requêtes SELECT qui retourne une
instance de l'objet ResultSet contenant le résultat de la
requête
✓executeUpdate() pour les requêtes de modification de base
(INSERT, UPDATE, DELETE, CREATE TABLE, DROP TABLE) qui
retourne un entier correspondant aux nombres de tuples traités
✓execute() procédures stockées (cas rare)
Les deux premières méthodes prennent en argument une chaîne
(String) indiquant la requête à effectuer
Exemples
st.executeQuery("SELECT * FROM matiere WHERE
abbreviation='BD';");
int nb = st.executeUpdate("DROP TABLE MYTABLE");
Remarque:
si une requête ne peut s'exécuter (erreur de syntaxe et autres),
une exception SQLException est levée
Traiter les données renvoyées
L'objet ResultSet retourné lors d'une requête
executeQuery() permet d'accéder aux champs de tuples
sélectionnés
Seules les données demandées sont transférées en mémoire dans
le driver JDBC. Il faut donc les lire et les stocker en mémoire pour
un usage ultérieur
ResultSet rs = st.executeQuery("SELECT * FROM
matiere WHERE abreviation='BD';");
L’objet resultSet
L'objet ResultSet pointe sur enregistrements associés à la
requête
Au départ l'objet ResultSet pointe avant le premier résultat de
la requête
On peut parcourir les tuples résultants de différentes manières:
méthodes next(), previous(), first(), last() ...
Tant qu'il existe un enregistrement à lire les méthodes next() et
false() renvoient true
L’objet resultSet
Une fois que l'on est sur l'enregistrement voulu, on peut se servir
de cet objet ResultSet pour récupérer le contenu d'un
enregistrement
Les colonnes sont référencées par
✓ un numéro commençant à 1, ou
✓ leur nom
Types de données
Afin d'éviter un problème de conversion de données il existe des
méthodes permettant de récupérer le contenu d'une colonne
Méthode de la forme getXXX() correspondant aux types de
données de la colonne en question
Le XXX de getXXX() est le nom du type java correspondant
Chaque driver a des correspondances entre les types SQL du
SGBDR et les types JDBC
Le programmeur est responsable du choix des méthodes : une
exception SQLException est générée en cas d'erreur
Exemples
rs est de type ResultSet
int val = rs.getInt(3);
String p = rs.getString(“Produit");
double d = rs.getDouble(“Prix");
Correspondance des types
Type JDBC
Type JAVA
CHAR,VARCHAR
String
java.math.BigDecimal
NUMERIC, DECIMAL
java.math.BigDecimal
BINARY,VARBINARY
byte[]
BIT
boolean
INTEGER
int
BIGINT
long
REAL
float
DOUBLE
oat
double
DATE
java.sql.Date
TIME
java.sql.Time
Les valeurs nulles
On peut récupérer le cas ou une valeur d'un enregistrement est
null
Pour récupérer les valeurs NULL de la base, utiliser la méthode
wasNull de la classe ResultSet qui renvoie true si on vient de
lire un NULL
Les méthodes getXXX() convertissent une valeur NULL en valeur
acceptable
0 dans le cas d'un entier, false dans celui d'un booleen, null
pour une référence
Fermer les différents espaces
Pour terminer proprement un programme, il faut fermer les
différents espaces ouverts
Chaque objet (ResultSet, Connection, Statement) possède
une méthode close à appeler.
Méta-données d’une requête
La méthode getMetaData() de la classe ResultSet permet
d'obtenir des informations sur les types de données du
ResultSet
Renvoie une instance de ResultSetMetaData
On peut connaître entre autres:
✓ le nombre de colonnes : getColumnCount()
✓ le nom d'une colonne : getColumnName(int col)
✓ le type d'une colonne : getColumnType(int col)
✓ Si un NULL peut être stocké dans une colonne: isNullable()
✓ ...
Exemple
Resultset rs = stmt.executeQuery("SELECT * FROM emp");
ResultSetMetaData rsmd = rs.getMetatData();
int nbColonnes = rsmd.getColumnCount();
for(int i = 1; i <= nbColonnes; i++) {
/* colonnes numerotees a partir de 1 (et non 0) */
String nomCol = rsmd.getColumnName(i);
System.out.println(nomCol + " ");
}
Accès aux méta-données
De la même façon, on peut récupérer les informations sur la base
de données elle même
Il faut utiliser la méthode getMetaData de la classe
connection
Renvoie une instance de la classe DatabaseMetaData
On peut connaître entre autres :
✓les tables de la base : getTables()
✓le nom de l'utilisateur : getUser()
✓.....
Résumé
Driver
Enregistre
DriverManager
Fournit
Connexion
Crée
Statement
Fournit
DataBaseMetaData
Retrouve
ResultSet
Fournit
PreparedStatement
CallableStatement
ResultSetMetaData
Requêtes pré-compilées
L'objet PreparedStatement envoie une requête avec
paramètres à la BD pour pré-compilation et spécifiera le moment
venu la valeur des paramètres
Plus rapide que les requêtes Statement classiques
Permet l'exécution d'une même requête avec différents
paramètres
Les SGBDR n'acceptent pas toutes les requêtes pré-compilées
Création
La méthode prepareStatement() de l'objet Connection crée
une instance de PreparedStatement
Les arguments dynamiques sont spécifiés avec ?
ils sont ensuite positionnés par les méthodes setXXX(). Ces
méthodes prennent deux arguments :
✓ un entier indiquant le numéro relatif de l'argument de la
requête
✓ la valeur à positionner
Une fois les valeurs positionnées on exécute la requête avec
executeUpdate() ou executeQuery()
Exemple
PrepareStatement ps = c.prepareStatement(
"UPDATE emp SET sal = ? where name = ?");
int count;
for(int i = 0; i < 10; i++) {
ps.setFloat(1,salary[i]);
ps.setString(2,name[i]);
ps.executeUpdate();
... }
Validation de transaction
Par défaut, un commit est effectué après chaque requête SQL :
Mode Auto Commit
On peut repasser en mode Manuel :
connection.setAutoCommit(false);
L'application doit alors renvoyer a la base un commit pour
rendre permanents les changements occasionnés par la
transaction
connection.commit();
Annulation de transaction
De même, on peut annuler une transaction
Il suffit d'envoyer à la base un rollback
retauration.rollback();
Restauration de la base comme elle était après le dernier commit
Exceptions
Une exception SQLException est générée dès qu'une connexion
ou qu'une requête SQL ne se passe pas correctement
La méthode getMessage() donne le message en clair de
l'erreur
Téléchargement