Interface de programmation Application / BD - … · Département de génie logiciel et des TI...

34
Département de génie logiciel et des TI LOG660 - Bases de données de haute performance Interface de programmation Application / BD Hiver 2011 C. Desrosiers

Transcript of Interface de programmation Application / BD - … · Département de génie logiciel et des TI...

Département de génie logiciel et des TI

LOG660 - Bases de données de haute performance

Interface de programmation Application / BD

Hiver 2011 C. Desrosiers

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 2

Interface entre SQL et un programme

  SQL incomplet

  Défaut d'impédance (impedance mismatch)

–  modèle de données BD ≠

–  modèle de données du langage de programmation

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 3

Interface programmatique (Call-Level Interface - SQL/CLI)

  API spécifique au SGBD

–  e.g. Oracle Call Interface (OCI)

–  non portable

  API normalisée

–  standard de facto ODBC

  développé par Microsoft pour le C

–  pilote ODBC pour client/serveur

–  SQL/CLI de SQL:1999 inspirée de ODBC

–  JDBC pour Java

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 4

SQL enchâssé (Embedded SQL)

 Code SQL dans le source du langage hôte   Syntaxe spéciale  Pré-compilation

–  Oracle : pro*C/C++, pro*COBOL, …, SQLJ

 Moins portable –  pré-compilateur spécifique au SGBD –  traduit en API du SGBD

 SQLJ (partie 0) traduit en API standard JDBC

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 5

Extension procédurale à SQL (Persistent Stored Modules - SQL/PSM)

  SQL + –  structures de contrôle –  procédures, fonctions, packages –  support direct des types SQL pour les variables –  exécution au niveau serveur de BD

 Oracle –  PL/SQL

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 6

Bloc PL/SQL

[DECLARE déclaration [déclaration] ...]

BEGIN séquenceEnoncés[EXCEPTION exception_énoncé [exception_énoncé] ...]END

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 7

Exécution d’un bloc sous SQL*plus

SQL> DECLARE 2 laQuantitéEnStock Article.quantitéEnStock%TYPE; 3 BEGIN 4 SELECT quantitéEnStock INTO laQuantitéEnStock 5 FROM Article 6 WHERE noArticle = 10; 7 IF laQuantitéEnStock = 0 THEN 8 DBMS_OUTPUT.PUT_LINE('L article est en rupture de stock'); 9 ELSE 10 DBMS_OUTPUT.PUT('Quantité en stock :'); 11 DBMS_OUTPUT.PUT_LINE(laQuantitéEnStock); 12 END IF; 13 EXCEPTION 14 WHEN NO_DATA_FOUND THEN 15 DBMS_OUTPUT.PUT_LINE('Numéro d article inexistant'); 16 WHEN OTHERS THEN 17 RAISE_APPLICATION_ERROR(-20001,'Erreur soulevée par le SELECT'); 18 END; 19 /Quantité en stock :20

PL/SQL procedure successfully completed.

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 8

Déclaration de variables PL/SQL (DECLARE)

leNoClient Client.noClient%TYPE;

leNoClient INTEGER;

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 9

Transfert d'une valeur de colonne d'un SELECT dans une variable (clause INTO)

SELECT noClient, dateCommandeINTO leNoClient, laDateCommandeFROM CommandeWHERE noCommande = leNoCommande;

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 10

Affectation en PL/SQL

laQuantitéEnAttente:= laQuantitéCommandée -laQuantitéLivrée;

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 11

Structure de contrôle IF

IF (laQuantitéLivrée IS NULL) THENDBMS_OUTPUT.PUT_LINE(' livraison en attente');

ELSElaQuantitéEnAttente:= laQuantitéCommandée -laQuantitéLivrée;IF (laQuantitéEnAttente = 0) THEN

DBMS_OUTPUT.PUT_LINE(' livraison complétée');ELSE

DBMS_OUTPUT.PUT (' quantité en attente :');DBMS_OUTPUT.PUT_LINE(laQuantitéEnAttente);

END IF ;END IF ;

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 12

Boucles (LOOP, FOR, WHILE)

LOOP séquenceEnoncésEND LOOP ;

FOR indice IN [REVERSE] valeurInitiale..valeurFinale LOOPséquenceEnoncés

END LOOP ;

WHILE condition LOOP séquenceEnoncésEND LOOP ;

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 13

Traitement d'exception (EXCEPTION, RAISE)

 Déclarer

  Soulever

 Attraper

nomException EXCEPTION;

RAISE nomException

WHEN nomException THENséquenceÉnoncés

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 14

Curseur PL/SQL (CURSOR)

CURSOR lignesCommande(unNoCommande Commande.noCommande%TYPE)IS SELECT noArticle, quantité FROM LigneCommande WHERE LigneCommande.noCommande = unNoCommande ;

OPEN lignesCommande(leNoCommande);-- Le OPEN ouvre le CURSOR en lui passant les paramètres

LOOPFETCH lignesCommande INTO leNoArticle, laQuantitéCommandée;-- Le FETCH retourne la ligne suivante

EXIT WHEN lignesCommande%NOTFOUND;-- %NOTFOUND est un attribut du CURSOR qui permet de déterminer-- si le FETCH a atteint la fin de la table

END LOOP;

-- Le CLOSE ferme le CURSORCLOSE lignesCommande;

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 15

Boucle FOR pour curseur PL/SQL

FOR uneLigne IN lignesCommande(leNoCommande) LOOP

DBMS_OUTPUT.PUT('noArticle :');DBMS_OUTPUT.PUT(uneLigne.noArticle);DBMS_OUTPUT.PUT(' quantité commandée:');DBMS_OUTPUT.PUT(uneLigne.quantité);

-- Chercher la quantité déjà livréeSELECT SUM(quantitéLivrée)INTO laQuantitéLivréeFROM DétailLivraisonWHERE noArticle = uneLigne.noArticle AND

noCommande = leNoCommande ;

IF (laQuantitéLivrée IS NULL) THENDBMS_OUTPUT.PUT_LINE(' livraison en attente');

ELSElaQuantitéEnAttente:= uneLigne.quantité -laQuantitéLivrée;IF (laQuantitéEnAttente = 0) THEN

DBMS_OUTPUT.PUT_LINE(' livraison complétée');ELSE

DBMS_OUTPUT.PUT (' quantité en attente :');DBMS_OUTPUT.PUT_LINE(laQuantitéEnAttente);

END IF ;END IF ;

END LOOP;

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 16

Procédures et fonctions PL/SQL stockées

SQL> CREATE FUNCTION fQuantitéEnStock 2 (unNoArticle Article.noArticle%TYPE) 3 RETURN Article.quantitéEnStock%TYPE IS 4 5 uneQuantitéEnStock Article.quantitéEnStock%TYPE; 6 BEGIN 7 SELECT quantitéEnStock 8 INTO uneQuantitéEnStock 9 FROM Article 10 WHERE noArticle = unNoArticle; 11 RETURN uneQuantitéEnStock; 12 END fQuantitéEnStock; 13 14 /

Function created.

SQL> select fQuantitéEnStock(10) from dual;

FQUANTITÉENSTOCK(10)-------------------- 10

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 17

Procédure stockée

SQL> CREATE PROCEDURE pModifierQuantitéEnStock 2 (unNoArticle Article.noArticle%TYPE, 3 nouvelleQuantitéEnStock Article.quantitéEnStock%TYPE) IS 4 BEGIN 5 UPDATE Article 6 SET quantitéEnStock = nouvelleQuantitéEnStock 7 WHERE noArticle = unNoArticle; 8 END pModifierQuantitéEnStock; 9 /

Procedure created.

SQL> EXECUTE pModifierQuantitéEnStock(10,20);

PL/SQL procedure successfully completed.

SQL> SELECT * FROM Article WHERE noArticle = 10;

NOARTICLE DESCRIPTION PRIXUNITAIRE QUANTITÉENSTOCK---------- -------------------- ------------ --------------- 10 Cèdre en boule 10,99 20

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 18

Privilèges dans une routine stockée

 Privilèges de l'appelant (invoker rights)

 Privilèges de la routine (definer rights) –  privilèges du créateur –  par défaut

CREATE PROCEDURE pModifierQuantitéEnStock(unNoArticle Article.noArticle%TYPE, nouvelleQuantitéEnStock Article.quantitéEnStock%TYPE)AUTHID CURRENT_USER IS

BEGIN UPDATE Article SET quantitéEnStock = nouvelleQuantitéEnStock WHERE noArticle = unNoArticle;END pModifierQuantitéEnStock;

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 19

Exemple privilège de l’appelant SQL> connect godin/oracle Connected. SQL> CREATE OR REPLACE PROCEDURE pModifierQuantitéEnStock 2 (unNoArticle Article.noArticle%TYPE, 3 nouvelleQuantitéEnStock Article.quantitéEnStock%TYPE) 4 AUTHID CURRENT_USER IS 5 BEGIN 6 UPDATE Article 7 SET quantitéEnStock = nouvelleQuantitéEnStock 8 WHERE noArticle = unNoArticle; 9 END pModifierQuantitéEnStock; 10 / Procedure created. SQL> grant execute on pModifierQuantitéEnStock to public; Grant succeeded. SQL> connect test/oracle Connected. SQL> EXECUTE godin.pModifierQuantitéEnStock (10,500); PL/SQL procedure successfully completed. SQL> select * from article; NOARTICLE DESCRIPTION PRIXUNITAIRE QUANTITÉENSTOCK ---------- -------------------- ------------ --------------- 10 Cèdre en boule 10,99 500 20 Sapin 12,99 10 … SQL> select * from godin.article; select * from godin.article * ERROR at line 1: ORA-00942: table or view does not exist

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 20

Exemple privilège du créateur SQL> connect godin/oracle Connected. SQL> CREATE OR REPLACE PROCEDURE pModifierQuantitéEnStock 2 (unNoArticle Article.noArticle%TYPE, 3 nouvelleQuantitéEnStock Article.quantitéEnStock%TYPE) 4 IS 5 BEGIN 6 UPDATE Article 7 SET quantitéEnStock = nouvelleQuantitéEnStock 8 WHERE noArticle = unNoArticle; 9 END pModifierQuantitéEnStock; 10 / Procedure created. SQL> grant execute on pModifierQuantitéEnStock to public; Grant succeeded. SQL> connect test/oracle Connected. SQL> EXECUTE godin.pModifierQuantitéEnStock (10,700); PL/SQL procedure successfully completed. SQL> select * from article; NOARTICLE DESCRIPTION PRIXUNITAIRE QUANTITÉENSTOCK ---------- -------------------- ------------ --------------- 10 Cèdre en boule 10,99 500 20 Sapin 12,99 10 …

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 21

Exemple privilège du créateur (suite)

SQL> select * from godin.article; select * from godin.article * ERROR at line 1: ORA-00942: table or view does not exist SQL> connect godin/oracle Connected. SQL> select * from article; NOARTICLE DESCRIPTION PRIXUNITAIRE QUANTITÉENSTOCK ---------- -------------------- ------------ --------------- 10 Cèdre en boule 10,99 700 20 Sapin 12,99 10 40 Épinette bleue 25,99 10 50 Chêne 22,99 10 60 Érable argenté 15,99 10 70 Herbe à puce 10,99 10 80 Poirier 26,99 10 81 Catalpa 25,99 10 90 Pommier 25,99 10 95 Génévrier 15,99 10 10 rows selected.

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 22

Package PL/SQL CREATE PACKAGE nomPaquetage AS

listeDesSignaturesDesFonctions&ProcéduresEND nomPaquetage ;

CREATE PACKAGE BODY nomPaquetage ASdélaration [déclaration]…

BEGIN séquenceÉnoncésInitialisationEND nomPaquetage;

nomPaquetage.nomObjet

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 23

JDBC

 API standard pour JAVA   http://java.sun.com/products/jdbc/  Ensemble de classes  Besoin d ’installer un pilote JDBC dans

l ’environnement JAVA

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 24

Architecture pour les pilotes JDBC

API JDBC

Type 1Passerelle JDBC-

ODBC

Application Java(import java.sql.*)

Type 2Partie Java

Pilote ODBC(e.g. pilote ODBC

Oracle)

Type 3Pilote JDBCgénérique

Type 4Pilote JDBC tout

Java(e.g. Oracle thin)

ServeurJDBC

API client duSGBD

(e.g. ocijdbc8.dllpour Oracle)

Serveur de BD

Type ?Oracle server-

side thin etinternal driver

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 25

Chargement d'un pilote JDBC et établissement d'une connexion

  Charger les pilotes JDBC d ’ Oracle

  Établir une connexion avec le pilote OCI8 pour un serveur Oracle local

Class.forName ("oracle.jdbc.driver.OracleDriver");

Connection uneConnection =DriverManager.getConnection("jdbc:oracle:oci8:@", "toto", "secret");

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 26

Création d’un énoncé SQL (Statement)

Statement

executeQuery(arg0 : String) : ResultSetexecuteUpdate(arg0 : St ring) : intclose() : voidgetMaxFieldSize() : intsetMaxFieldSize(arg0 : int) : voidgetMaxRows() : intsetMaxRows(arg0 : int) : voidsetEscapeProcessing(arg0 : boolean) : voidgetQueryTimeout() : intsetQueryTimeout(arg0 : int) : voidcancel() : voidgetWarnings() : SQLWarningclearWarnings() : voidsetCursorName(arg0 : String) : voidexecute(arg0 : String) : booleangetResultSet() : ResultSetgetUpdateCount() : intgetMoreResults() : booleansetFetchDirection(arg0 : int) : voidgetFetchDirection() : intsetFetchSize(arg0 : int) : voidgetFetchSize() : intgetResultSetConcurrency() : intgetResultSetType() : intaddBatch(arg0 : String) : voidclearBatch() : voidexecuteBatch() : int[]getConnection() : Connection

<<Interface>>

Statement unEnoncéSQL = uneConnection.createStatement ();

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 27

Exécution d'une opération de mise à jour (INSERT, DELETE, UPDATE)

import java.sql.*;

class ClientInsertJDBC{ public static void main (String args []) throws SQLException, ClassNotFoundException, java.io.IOException { // Charger le pilote JDBC d'Oracle Class.forName ("oracle.jdbc.driver.OracleDriver");

// Connexion à une BD Connection uneConnection = DriverManager.getConnection ("jdbc:oracle:oci8:@", "godin", "oracle");

// Création d'un énoncé associé à la Connection Statement unEnoncéSQL = uneConnection.createStatement ();

// Insertion d'une ligne dans la table Client int n = unEnoncéSQL.executeUpdate ("INSERT INTO CLIENT " + "VALUES (100, 'G. Lemoyne-Allaire', '911')"); System.out.println ("Nombre de lignes inserees:" + n);

// Fermeture de l'énoncé et de la connexion unEnoncéSQL.close(); uneConnection.close(); }}

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 28

Exécution d'un SELECT (ResultSet)

… Début analogue à l'exemple précédent

// Création d'un énoncé associé à la Connexion Statement unEnoncéSQL = uneConnection.createStatement();

// Exécution d'un SELECT ResultSet résultatSelect = unEnoncéSQL.executeQuery ("SELECT noClient, nomClient "+ "FROM CLIENT " + "WHERE noClient > 40");

// Itérer sur les lignes du résultat du SELECT et extraire les valeurs // des colonnes dans des variables JAVA

while (résultatSelect.next ()){int noClient = résultatSelect.getInt ("noClient");

String nomClient = résultatSelect.getString ("nomClient"); System.out.println ("Numéro du client:" + noClient); System.out.println ("Nom du client:" + nomClient); } }}

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 29

Support des types SQL:1999 sous JDBC 2

CREATE TABLE tableBlob (idBlob INTEGER PRIMARY KEY,imageBLOB)

// Chercher le BLOB locator ResultSet unResultSet = unEnoncéSQL.executeQuery ("SELECT * FROM tableBlob WHERE idBlob = 1"); if (unResultSet.next()){

int idBlob = unResultSet.getInt(1); Blob unBlob = unResultSet.getBlob(2);

// Chercher la taille du BLOB et l'afficher int taille = (int)unBlob.length(); System.out.println("Taille du BLOB" + taille);

// Lire le BLOB dans un tableau d'octets byte octets[] = unBlob.getBytes(1, taille);

// Créer un fichier contenant les octets lus FileOutputStream unFichier = new FileOutputStream("C:/forte4j/Development/ExemplesJDBC/CopieCoq1.gif"); unFichier.write(octets); unFichier.close();

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 30

Compilation et exécutions multiples avec la classe PreparedStatement

Statement unEnoncéSQL = uneConnection.createStatement();ResultSet résultatSelect = unEnoncéSQL.executeQuery ("SELECT noClient, nomClient "+ "FROM CLIENT " + "WHERE noClient > 40");

PreparedStatement unEnoncéSQL = uneConnection.prepareStatement("SELECT noClient, nomClient "+ "FROM CLIENT " + "WHERE noClient > 40");

ResultSet résultatSelect = unEnoncéSQL.executeQuery();

PreparedStatement unEnoncéSQL = uneConnection.prepareStatement("SELECT noClient, nomClient "+

"FROM CLIENT " + "WHERE noClient > ?");unEnoncéSQL.setInt(1,40);ResultSet résultatSelect = unEnoncéSQL.executeQuery();

  Compilation + exécution combinée au executeQuery

  Compilation au prepareStatement

  Compilation avec paramètres CallableStatement

PreparedStatement

Statement

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 31

Exécution en lot (batch) sous JDBC 2

// Création d'un PreparedStatement associé à la Connection PreparedStatement unEnoncéSQL = uneConnection.prepareStatement ("INSERT INTO Client VALUES(?,?,?)");

// Ajout d'un INSERT dans le lot unEnoncéSQL.setInt(1,90); unEnoncéSQL.setString(2,"Edgar Degas"); unEnoncéSQL.setString(3,"(222)222-2222"); unEnoncéSQL.addBatch();

// Ajout d'un autre INSERT dans le lot unEnoncéSQL.setInt(1,100); unEnoncéSQL.setString(2,"Claude Monet"); unEnoncéSQL.setString(3,"(111)111-1111"); unEnoncéSQL.addBatch();

// Exécution du lot en un appel int [] résultats = unEnoncéSQL.executeBatch();

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 32

Exécution d'une procédure ou fonction stockée (CallableStatement)

// Création d'un appel de fonction associé à la Connection CallableStatement unCall =

uneConnection.prepareCall("{ ? = call fQuantitéEnStock(?)}");

// Spécification du paramètre d'entrée unCall.setInt(2,10); // Inscription de la sortie unCall.registerOutParameter(1, java.sql.Types.INTEGER); // Exécution de l'appel unCall.execute(); // Récupération de la sortie int laQuantite = unCall.getInt(1);

System.out.println("Quantité en stock :"+laQuantite); }; unCall.close(); uneConnection.close();

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 33

Appel de procédure stockée

CallableStatement unCall =uneConnection.prepareCall("{call pModifierQuantitéEnStock(?,?)}");

// Spécification des paramètres d'entrée unCall.setInt(1,10); unCall.setInt(2,20); // Exécution de l'appel unCall.execute(); unCall.close(); uneConnection.close();

Département de génie logiciel et des TI © R. Godin, C. Desrosiers - Hiver 2011 34

Gestion des transactions

 Par défaut : auto-commit  Pour modifier

 Pour un commit explicite :

 Pour un rollback :

uneConnection.setAutoCommit(false);

uneConnection.commit();

uneConnection.rollback();