Vous êtes sur la page 1sur 18

Plan de cette partie

JDBC avanc
Universit de Nice - Sophia Antipolis
Version 1.15.6 11/10/11 Richard Grin

Gnration des cls ResultSet avanc RowSet Regrouper les modifications Types de donnes SQL 3, BLOB et CLOB Pool de connexions, source de donnes Transaction distribue

R. Grin

JDBC avanc

page 2

Gnration de cls
La gnration automatique de cls nest pas standardis Oracle utilise des squences (comme DB2 et PostgreSQL) Dautres SGBD utilisent dautres mthodes : n attribut AUTO_INCREMENT sur une colonne pour MySQL n attribut IDENTITY pour SQL Server

n
R. Grin JDBC avanc page 3 R. Grin

Gnration automatique de cls et JDBC

JDBC avanc page 4

Une situation courante


Une situation peut ncessiter la connaissance dune cl gnre automatiquement Exemple : une facture est compose dune table pour len-tte de la facture (numro de la facture, client, date,) et dune table pour les lignes de la commande Pour crire les lignes de la facture on a besoin de connatre la cl de len-tte de la facture (chaque ligne contient une cl trangre vers cette cl de len-tte) et cette cl est gnre automatiquement par le SGBD

R. Grin JDBC avanc page 5

Rcupration des cls gnres


La rcupration dune cl automatique ne devrait pas ncessiter de lancer une requte SQL avec un accs la base de donnes (toujours coteux) Il est possible dindiquer que lon souhaite recevoir les cls gnres par lexcution dune requte SQL par Statement ou PreparedStatement

R. Grin

JDBC avanc

page 6

2 tapes pour rcuprer les cls gnres par un Statement insert


1.

getGeneratedKeys

Linterface Statement contient une mthode ResultSet getGeneratedKeys() Cette mthode sappelle aprs lexcution dun insert (par executeUpdate ou execute)

2.

Indiquer au driver que lon souhaite rcuprer les cls qui seront gnres automatiquement durant lexcution du insert Aprs lexcution du insert, utiliser la mthode ResultSet getGeneratedKeys() pour rcuprer les cls

Elle renvoie toutes les cls gnres par lordre SQL, indpendamment de la manire dont elles ont t gnres Le ResultSet renvoy est vide si aucune cl na t gnre
R. Grin JDBC avanc page 8

R. Grin

JDBC avanc

page 7

Lecture des cls gnres

Paramtre pour les cls gnres

La mthode getGeneratedKeys ne marche que si on indique, au moment de lexcution du insert, que lon souhaite rcuprer les cls Pour Statement, il suffit pour cela de passer un 2me paramtre execute ou executeUpdate Pour PreparedStatement, on passe ce 2me paramtre prepareStatement (au moment de la cration du PreparedStatement)
JDBC avanc page 9

Ce 2me paramtre peut tre n soit la valeur Statement.RETURN_GENERATED_KEYS ; en ce cas, le driver essaie de deviner quelles colonnes contiennent les cls n soit un tableau int[] ou String[] indiquant les colonnes du insert qui contiennent les cls gnrs

R. Grin

R. Grin

JDBC avanc

page 10

Exemple
Ajout dune nouvelle facture dans la base On a besoin de la cl gnre pour la facture pour la mettre en cl trangre dans les lignes de la facture

Exemple avec Oracle


Statement stmt = conn.createStatement(); // Ne pas oublier le 2me paramtre optionnel stmt.executeUpdate( "INSERT INTO facture (id_facture,...) " + "VALUES(sequence.nextval,...)", new String[] { "id_facture" }); ResultSet rsCles = stmt.getGeneratedKeys(); if (rsCles.next()) { cle = rsCles.getInt(1); } // cle utilis pour insrer les lignes // de la facture
R. Grin JDBC avanc page 12

R. Grin

JDBC avanc

page 11

Cls gnres et Oracle

Nouvelles possibilits de JDBC 2.0 et 3.0


Pour Oracle, si on utilise une squence pour gnrer la cl de la facture, on peut aussi utiliser sequence.currval dans les ordres insert des lignes de la facture

Parcourir un ResultSet dans les 2 sens

Modifier les donnes de la base correspondant aux donnes renvoyes par un ResultSet directement par des mthodes de ResultSet, sans utiliser explicitement SQL Regrouper plusieurs ordres SQL pour les envoyer au SGBD Pools de connexions
R. Grin JDBC avanc page 14

R. Grin

JDBC avanc

page 13

Types de ResultSet

ResultSet

3 types de ResultSet : n TYPE_FORWARD_ONLY : ne peut pas tre parcouru que dans un sens n TYPE_SCROLL_INSENSITIVE : peut tre parcouru dans les 2 sens, mais ne reflte pas les modifications faites dans la base aprs la rcupration du ResultSet n TYPE_SCROLL_SENSITIVE : peut tre parcouru dans les 2 sens, et reflte les modifications faites dans la base aprs la rcupration du ResultSet
JDBC avanc page 16

R. Grin

JDBC avanc

page 15

R. Grin

Types de ResultSet
Paralllement ces types, un ResulSet peut tre n CONCUR_READ_ONLY : on ne peut pas modifier les donnes en passant par le ResultSet n CONCUR_UPDATABLE : on peut modifier les donnes en passant par le ResultSet On peut donc avoir 6 types (3 x 2) de ResultSet En fait, tous les drivers ne les permettent pas avec de bonnes performances

R. Grin JDBC avanc page 17

Choix dun type de ResultSet

Des variantes des mthodes createStatement, prepareStatement et prepareCall de la classe Connection permettent de faire ce choix (consultez la javadoc des ces mthodes)

R. Grin

JDBC avanc

page 18

Permettre le parcours double sens dans un ResultSet

Statement stmt = conn.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); ResultSet srs = stmt.executeQuery( "SELECT nomE, salaire FROM emp");

Les transparents suivants montrent les possibilits offertes par les ResultSet scrollable (ceux qui permettent de se dplacer o lon veut dans les lignes)

R. Grin

JDBC avanc

page 19

R. Grin

JDBC avanc

page 20

Parcours en avant dans un ResultSet


// A ajouter si on ne vient pas de rcuprer // le ResultSet : srs.beforeFirst() while (srs.next()) { String nomE = srs.getString("nomE"); double salaire = srs.getFloat("salaire"); System.out.println(nomE + " ; " + salaire); }

Parcours en arrire dans un ResultSet


srs.afterLast(); while (srs.previous()) { String nomE = srs.getString("nomE"); double salaire = srs.getFloat("salaire"); System.out.println(nomE + " ; " + salaire); }

R. Grin

JDBC avanc

page 21

R. Grin

JDBC avanc

page 22

Positionnement absolu et relatif dans un ResultSet

ResultSet modifiable
Si le select et si la colonne du select le permettent, il est possible de modifier la valeur dune colonne dune ligne renvoye par le select et denregistrer cette modification dans la base de donnes Sinon, la mthode updateXXX ou la mthode updateRow lancera une exception

srs.absolute(-2); // avant-dernire ligne srs.absolute(4); int numLigne = srs.getRow(); // numLigne = 4 srs.relative(-3); int numLigne = srs.getRow(); // numLigne = 1 srs.relative(2); int numLigne = srs.getRow(); // numLigne = 3 Les numros de lignes commencent 1 (pas 0)
R. Grin JDBC avanc page 23

R. Grin

JDBC avanc

page 24

ResultSet modifiable

Le select dun ResultSet modifiable doit (cf. conditions sur les vues) n ne pas contenir de jointure ou de group by

Cration dun ResultSet modifiable


Statement stmt = con.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet uprs = stmt.executeQuery( "SELECT matr, nomE, salaire FROM emp");

n contenir la cl primaire de la table Les expressions des colonnes modifies doivent tre de simples noms de colonnes de tables Exemple de colonne non modifiable : une colonne qui contient une expression avec une fonction SQL

R. Grin

JDBC avanc

page 25

R. Grin

JDBC avanc

page 26

Modifier des lignes par un ResultSet


uprs.last(); uprs.updateDouble("salaire", 10000); uprs.cancelRowUpdates(); // annule uprs.updateDouble(2, 12000); uprs.updateRow(); // enregistre modifs dans BD

Insrer des lignes par un ResultSet Va dans le buffer


dans lequel seront uprs.moveToInsertRow(); ranges les valeurs de la nouvelle ligne uprs.updateInt("matr", 150); uprs.updateString("nomE", "Kleber"); uprs.updateDouble("salaire", 10000); . . . uprs.insertRow();

Ne pas oublier updateRow() ! updateNull permet de donner la valeur NULL


R. Grin JDBC avanc page 27 R. Grin JDBC avanc page 28

Supprimer la ligne courante dun ResultSet

Validation des modifications


Comme pour les autres commandes de modification des donnes de la base, les modifications doivent tre valides (resp. invalides) par un appel de la mthode commit() (resp. rollback()) de la connexion en cours (sauf si la connexion est en mode autocommit, ce qui nest pas recommand)

uprs.absolute(4); uprs.deleteRow();

R. Grin

JDBC avanc

page 29

R. Grin

JDBC avanc

page 30

RowId
java.sql.RowId est un nouvelle interface Java introduite par JDBC 4 Ce type permet de stocker un identificateur pour une ligne dun ResultSet afin de modifier par la suite la ligne en la dsignant par cet identificateur RowId nest pas support par tous les SGBD ; getRowIdLifeTime() de DataBaseMetaData indique si RowId est support, et la dure de vie dun RowId

R. Grin JDBC avanc page 31 R. Grin

RowSet

JDBC avanc

page 32

Prsentation
ResulSet qui a lavantage de se conformer au modle des Java Beans (srialisables, avec proprits, et observables par des couteurs) Reprsent dans lAPI par des interfaces, dont linterface racine javax.sql.RowSet hrite de ResultSet

Rowset dconnectable
Certains rowsets peuvent tre dconnects de la base aprs y avoir rcupr des donnes On peut alors modifier leurs donnes en mode dconnect Les rowsets peuvent ensuite se reconnecter et enregistrer les modifications dans la base

Le JDK 5 fournit des implmentations des diffrentes sous-interfaces de RowSet

R. Grin

JDBC avanc

page 33

R. Grin

JDBC avanc

page 34

Sous-interfaces de RowSet

JdbcRowSet
Cest essentiellement une enveloppe autour dun ResultSet, qui a les proprits dun Java bean Le rowset est modifiable (si le select le permet) et peut tre parcouru dans les 2 sens, mme sil enveloppe un resultSet qui ne le permettait pas Une implmentation est fournie avec la distribution Java : com.sun.rowset.JdbcRowSetImpl

R. Grin JDBC avanc page 36

Interfaces du paquetage javax.sql.rowset : n JDBCRowSet : rowset qui reste connect n CachedRowSet : rowset dconnectable n WebRowSet : fille de CachedRowSet qui peut se sauvegarder au format XML n JoinRowSet et FilterRowSet : filles de WebRowSet qui reprsentent des rowsets sur lesquels on peut effectuer des jointures et des slections quand ils sont dconnects
JDBC avanc page 35

R. Grin

JdbcRowSet

2 constructeurs : n avec un ResultSet en paramtre, pour envelopper un ResultSet existant n sans paramtre ; il faudra ensuite donner les informations pour la connexion la base et pour indiquer les donnes rcuprer

JdbcRowSet constructeur avec un paramtre ResultSet


Statement stmt = conn.createStatement(); ResultSet r = stmt.executeQuery("select ... "); JdbcRowSet rs = new JdbcRowSetImpl(r); while (rs.next()) { String nom = rs.getString(1); ... }
R. Grin JDBC avanc page 38

R. Grin

JDBC avanc

page 37

JdbcRowSet constructeur sans paramtre


JdbcRowSet rs = new JdbcRowSetImpl(); rs.setUsername(...); Initialisation rs.setPassword(...); rs.setUrl(...); rs.setCommand("select ... "); rs.execute(); Rcupration des donnes while (rs.next()) { String nom = rs.getString(1); ... }
R. Grin JDBC avanc page 39

Jokers dans la commande

Outre le ResultSet, un rowset cr avec le constructeur sans paramtre enveloppe aussi un PreparedStatement La chane passe en paramtre de setCommand peut comporter des joker ? Les valeurs correspondantes sont passes par des mthodes setXXX comme pour les PreparedStatement

R. Grin

JDBC avanc

page 40

Exemple
rs.setCommand("select nome, salaire " + " from employe where dept = ?"); rs.setInt(1, 20); rs.execute();

Erreur ne pas faire


Il ne faut pas confondre n les mthodes setXXX, par exemple setInt, qui servent donner des valeurs des paramtres de la commande n les mthodes updateXXX, par exemple updateInt, qui modifient les valeurs des lignes du rowset

R. Grin

JDBC avanc

page 41

R. Grin

JDBC avanc

page 42

Dplacement
Un rowset peut tre toujours tre parcouru dans les 2 sens La syntaxe est semblable celle de ResultSet

Modifications
Les donnes contenues dans le rowset peuvent tre modifies avec les mthodes habituelles de ResultSet Les mthodes commit et rollback de JDBCRowSet valident ou invalident les modification de la transaction courante Elles ne doivent tre utilises que si la transaction nest pas en autoCommit ; voir mthodes {get|set}AutoCommit de JDBCRowSet (par dfaut la connexion est en autoCommit)
R. Grin JDBC avanc page 44

R. Grin

JDBC avanc

page 43

Exemple de modifications
rs.absolute(4); rs.updateString("nom", "Dupond"); rs.updateRow(); rs.beforeFirst(); rs.next(); rs.updateInt(3, 135); rs.updateRow(); rs.commit()

RowSet dconnectable
Interface CachedRowSet Il se connecte la base juste le temps de rcuprer des donnes Il peut tre dconnect de la base ; il est alors possible de lire, modifier, supprimer des donnes du rowset (mme syntaxe que ResultSet) en local Il peut ensuite se reconnecter pour rpercuter dans la base les modifications faites pendant la dconnexion (mthode acceptChanges())
page 45 R. Grin JDBC avanc page 46

R. Grin

JDBC avanc

Remplir un CachedRowSet
Un CachedRowSet peut tre rempli avec les donnes dun ResultSet par la mthode populate(ResultSet) Cependant le plus simple est souvent dinitialiser le CachedRowSet pour quil puisse se connecter la base (mthodes setUsername, setPassword, setUrl ou setDataSourceName), et indiquer la commande pour rcuprer les donnes (setCommand) On peut ensuite lancer cette commande par la mthode execute

R. Grin JDBC avanc page 47

Pagination et taille des donnes


Un CachedRowSet garde ses donnes en mmoire ; lorsque les donnes de la base sont trop volumineuses il est possible de les rcuprer par morceaux (par pages) On peut fixer une taille pour la page Le nombre de lignes contenues dans un rowset est donne par la mthode size()

R. Grin

JDBC avanc

page 48

Exemple de pagination
CachedRowSet crs = CachedRowSetImpl(); crs.setPageSize(100); crs.execute(); while(crs.nextPage()) { // traite les lignes de la page courante while(crs.next()) { . . . Il existe aussi previousPage() } }

Connexion dun rowset


Lutilisation de la mthode populate ne renseigne pas le rowset sur la faon de se connecter la base Un connexion ncessite donc de renseigner le rowset avec les mthodes setUsername, setPassword ; la base est indique par son URL (setUrl) ou par son nom de source de donnes (setDataSourceName ; voir la section sur les sources de donnes plus loin dans ce support)
R. Grin JDBC avanc page 50

R. Grin

JDBC avanc

page 49

Connexions la base
Les mthodes execute et acceptChanges peuvent recevoir en paramtre une connexion la base En ce cas, cette connexion est utilise pour lire ou crire les donnes dans la base de donnes Sinon, le rowset ouvre une connexion en interne en utilisant les proprits de connexion du rowset

Modifier les donnes


Les donnes dun CachedRowSet peuvent tre modifies par divers mthodes updateXXX hrites de ResultSet Si la commande SQL le permet (contraintes semblables aux contraintes pour les vues modifiables), les modifications peuvent ensuite tre enregistres dans la base de donnes grce la mthode acceptChanges Le rowset se reconnecte la base, enregistre les modifications, puis se dconnecte
JDBC avanc page 52

R. Grin

JDBC avanc

page 51

R. Grin

Validation des modifications

Annulations de modifications
Les mthode undoInsert(), undoDelete() et undoUpdate() annulent la dernire modification de type insert, delete ou update effectue sur le rowset Il est ainsi possible dannuler plusieurs modifications qui ont t effectue depuis le dernier acceptChanges

Le plus souvent un commit est effectu chaque appel de acceptChanges (vrifiez-le dans la documentation de limplmentation du rowset)

R. Grin

JDBC avanc

page 53

R. Grin

JDBC avanc

page 54

Table modifie

Colonnes pour identifier les lignes


Si le CachedRowSet doit tre modifi et si on veut rpercuter ces modifications dans la base, il est indispensable dindiquer une (ou plusieurs) colonne du rowset qui servira didentificateur de ligne dans le rowset par la mthode setKeyColumns Le CachedRowSet pourra ainsi comparer les lignes du rowset avec les lignes de la base pour vrifier sil ny a pas de conflit

R. Grin JDBC avanc page 56

Avec certains SGBD (Oracle en particulier) il peut tre ncessaire dindiquer la table sur laquelle les modifications seront faites, par la mthode setTableName(String)

Avec dautres, le rowset peut avoir cette information par les mta donnes Des implmentations (Creator de Sun par exemple) utilisent cette mthode pour restreindre une seule table ce qui est insr dans la base lorsque le select du rowset concerne plusieurs tables (permet de modifier

des rowset qui ont un select avec jointure)


R. Grin JDBC avanc page 55

Code pour donner les colonnes identifiantes


// La 1re colonne du rowset identifiera rs.setKeyColumns(new int[] { 1 });

Code schmatique pour enregistrer les modifications


... // Plusieurs modifications des donnes rs.updateInt(2, 134); rs.updateRow(); ... try { rs.acceptChanges(); } catch(SyncProviderException e) { // Traitement des conflits ... // la suite au prochain exemple }
R. Grin JDBC avanc page 58

R. Grin

JDBC avanc

page 57

Conflits la reconnexion
Il peut y avoir des conflits au moment de la reconnexion la base si les donnes lues par le rowset depuis la dernire synchronisation avec la BD (acceptChanges) ont t modifies par un tiers pendant la dconnexion ; en ce cas il y un risque de perte de donnes Le traitement de ces conflits dpend de limplmentation du rowset Limplmentation de CachedRowSet fournie par le JDK utilise un blocage optimiste

R. Grin JDBC avanc page 59

Traitement optimiste des conflits


Quand le rowset rcupre les donnes dans la base, il enregistre ces donnes comme valeurs originales Au moment de lenregistrement des modifications (acceptChanges) ces valeurs originales sont compares aux valeurs actuelles de la base Il ny a pas de conflit sil y a galit ; en ce cas, les modifications sont enregistres et deviennent les nouvelles valeurs originales

R. Grin JDBC avanc page 60

10

Dtection des conflits


Sinon, cest que les donnes ont t modifies dans la base par un tiers, et il y a conflit acceptChanges lance alors une SyncProviderException

SyncResolver (1)
Interface et qui reprsente un objet qui contient des informations sur les conflits Cest un rowset (hrite de RowSet) qui reflte celui qui a eu des conflits (mmes lignes et colonnes), mais la place des valeurs du rowset, il y a null sil ny a pas de conflit sur la valeur, ou la valeur correspondante de la base de donnes en cas de conflit Contient aussi des informations comme le type dopration qui a caus le conflit
R. Grin JDBC avanc page 62

Lapplication peut alors demander lexception (mthode getSyncResolver) un SyncResolver pour laider rsoudre le conflit

R. Grin

JDBC avanc

page 61

SyncResolver (2)
Lapplication peut se dplacer dans le syncResolver pour avoir des informations sur chacun des conflits et pour les rsoudre Le dplacement peut se faire comme dans un rowset, avec en plus les mthodes nextConflict (resp. previousConflict) qui se positionne sur la prochaine (resp. prcdente) ligne sur laquelle il y a eu un conflit

R. Grin JDBC avanc page 63

Rsolution des conflits

Lapplication indique quelle valeur mettre dans la base de donnes par la mthode setResolvedValue(numCol, valeur) (ou setResolvedValue(nomCol, valeur) ) de SyncResolver Pour faire ce choix, lapplication peut demander la valeur actuellement dans la base de donnes getConflictValue(numCol) par getConflictValue(nomCol) de SyncResolver
JDBC avanc page 64

R. Grin

Exemple de traitement des conflits


SyncResolver resolv = e.getSyncResolver(); // Se positionne sur les lignes conflit while (resolv.nextConflict()) { if (resolv.getStatus() == SyncResolver.UPDATE_ROW_CONFLICT) { // Se positionne sur la ligne du // rowset lie ce conflit rs.absolute(resolv.getRow()); // Traitement des conflits dune ligne // dans le transparent suivant
R. Grin JDBC avanc page 65

Traitement des conflits dune ligne


int nbCol = rs.getMetaData().getColumnCount(); for (int j = 1; j <= nbCol; j++) { if (resolv.getConflictValue(j) != null) { Object valRs = rs.getObject(j); Object valResolv = resolv.getConflictValue(j); // Dcide ce quil faut faire . . . resolv.setResolvedValue(j, ...); } La valeur qui sera mise } dans la base R. Grin JDBC avanc page 66

11

Rsolution des confllits


La mthode setResolvedValue met la valeur originale du rowset la valeur actuelle de la base de donnes Ainsi, au prochain appel de la mthode acceptChanges, il ny aura plus de conflit (si la valeur dans la base na pas nouveau t modifie entre-temps) Attention, aprs avoir rsolu tous les conflits il ne faut pas oublier dappeler acceptChanges pour enregistrer dans la base les valeurs choisies

R. Grin JDBC avanc page 67

Autres possibilits (1)

release permet de vider un CachedRowSet : il ne contient plus aucune donnes (mais les informations sur la connexion ne sont pas touches)

R. Grin

JDBC avanc

page 68

Autres possibilits (2)

CachedRowSet permet aussi dajouter des observateurs et de les avertir si on change de ligne, si une ligne est modifie ou si le rowset est rempli avec dautres donnes (add/removeRowSetListener, cursorMoved, rowChanged, rowSetChanged) Il est aussi possible de rcuprer les donnes dans la base page par page lorsquil y a une grande quantit de donnes rcuprer (setPageSize, nextPage, previousPage)
JDBC avanc page 69 R. Grin

Regrouper des modifications

R. Grin

JDBC avanc

page 70

Performances
Dans les applications distribues il est important de rduire le nombre daccs distants aux bases de donnes pour amliorer les performances Les procdures stockes le permettent mais elles provoquent des problmes de portabilit On peut aussi regrouper plusieurs ordres SQL de type DML (insert, update, delete) pour les envoyer en une fois au SGBD Un driver JDBC peut ne pas implmenter cette fonctionnalit

R. Grin JDBC avanc page 71

Les mthodes
3 mthodes de linterface Statement (et donc aussi de ses sous-interfaces) permettent de manipuler les regroupements dordres SQL Elles peuvent lancer une SQLException void addBatch(String sql) : ajoute un ordre SQL la liste des ordres excuter int[] executeBatch() : excute les ordres SQL void clearBatch() : enlve toutes les ordres de la liste

R. Grin JDBC avanc page 72

12

Mthode executeBatch
Elle retourne un tableau dentiers qui indique le nombre de lignes modifies par chacun des ordres regroups ; la valeur peut tre ngative sil y a eu des problmes (voir javadoc pour plus de prcisions) Si une des commandes na pu tre excute correctement, une BatchUpdateException est renvoye ; les ordres SQL suivants sont excuts ou non suivant le driver (consulter la documentation du driver) ; on peut alors choisir de valider ou non la transaction

R. Grin JDBC avanc page 73

Exemple de regroupement
Statement stmt = conn.createStatement(); stmt.addBatch( "INSERT INTO DEPT " + "VALUES(70, 'Finances', 'Nancy')"); stmt.addBatch( "INSERT INTO DEPT " + "VALUES(80, 'Comptabilit', 'Nice')"); int[] nbLignes = stmt.executeBatch(); conn.commit();

R. Grin

JDBC avanc

page 74

Avec des requtes paramtres


PreparedStatement pstmt = conn.prepareStatement( "INSERT INTO DEPT VALUES(?, ?, ?)"); pstmt.setInt(1, 70); pstmt.setString(2, 'Finances'); pstmt.setString(3, 'Nancy'); pstmt.addBatch(); // Ajout dautres dpartements avec pstmt . . . int[] nbLignes = stmt.executeBatch(); conn.commit();
R. Grin JDBC avanc page 75 R. Grin

Nouveaux types de donnes de SQL3

JDBC avanc

page 76

Types de donnes de SQL3


JDBC supporte les types suivants de SQL3 : n BLOB (Binary Large Object) n CLOB (Character Large Object) n ARRAY n types structurs dfinis par lutilisateur n rfrences vers des instances de types structurs Les 3 derniers types sont tudis dans le cours sur JDBC et lobjet-relationnel

R. Grin JDBC avanc page 77

Blob et Clob
La plupart des SGBD fournissait dj les types BLOB et CLOB mais n ces types ntaient pas normaliss n laccs par JDBC n'tait pas normalis n les possibilits de manipulation de ces types taient restreintes (pas de recherche sur le contenu, par exemple) Il existe maintenant des types BLOB et CLOB et des interfaces Java Blob et Clob normaliss

R. Grin JDBC avanc page 78

13

Manipulation des LOB


Il existe plusieurs faons dcrire ou denregistrer de LOB, en passant par les interfaces BLOB et CLOB ou non (utiliser directement les mthodes de ResultSet qui travaillent sur des flots) Les transparents suivants prsentent quelques exemples (le traitement des exceptions a t enlev pour faciliter la lecture du code)

R. Grin JDBC avanc page 79

Interface Clob

On peut lire le contenu dune colonne de type Clob comme un flot de caractres ASCII ou Unicode par les mthodes (valable seulement jusqu la fin de la transaction)
InputStream getAsciiStream() Reader getCharacterStream()

On peut aussi lire un Clob comme une String ; on peut rechercher la position dune sous-chane de caractres dans un Clob, et extraire une partie du Clob :
long position(String sousCh, long debut) String getSubString(long pos, int longueur)
R. Grin JDBC avanc page 80

Exemple de rcupration de Clob


Statement stmt = conn.createStatement(); ResultSet rset = stmt.executeQuery( "select * from livre where isbn = 1421"); if (rset.next()) { Clob clob = rset.getClob("resume"); long l = clob.length(); // Affiche par paquets de 80 caractres for (long i = 0; i < l; i += 80) { String pRes = clob.getSubString(i, 80); System.out.println(pRes); } } // Il reste afficher le dernier paquet
R. Grin JDBC avanc page 81

Exemple de rcupration de Blob


requete = "select pdf from livre where id = 1421"; ResultSet rs = stmt.executeQuery(); if (rs.next()) { // Flot en lecture dans la base is = rs.getBinaryStream(1); // Flot en criture pour enregistrer le BLOB os = new FileOutputStream(nomFichier); byte[] buffer = new byte[1024]; int length = 0; while ((length = is.read(buffer)) != -1) { os.write(buffer, 0, length); } }
R. Grin JDBC avanc page 82

Enregistrer un Clob ou un Blob


La mthode setClob(int, Clob) de PreparedStatement met les objets de type Clob dans la base de donnes Pour les Blob, utiliser setBlob()

Avertissement
Les dernires parties de ce support ne sont que des survols rapides de possibilits avances offertes par JDBC et ses extensions Le but est de faire connatre lexistence de ces possibilits pour que le lecteur intress puisse approfondir leur tude par dautres sources

Chaque driver peut fournir un constructeur de Blob et de Clob, par exemple partir de tableau doctets ou de caractres On peut aussi enregistrer un Blob ou un Clob partir de tableaux, avec la mthode setObject() ou directement avec des flots

R. Grin JDBC avanc page 83

R. Grin

JDBC avanc

page 84

14

Politique de connexion Pools de connexions et sources de donnes


Une connexion une base de donnes est une ressource rare et coteuse qui ne peut tre partage par des threads Il faut donc rflchir la politique des connexions quand on crit une application qui utilise une base de donnes : n Quand faut-il ouvrir et fermer une connexion ? n Faut-il garder une connexion ouverte entre 2 utilisations de la base ?

page 85 R. Grin JDBC avanc page 86

R. Grin

JDBC avanc

Pool de connexions
Les choix pour une politique de connexion sont facilits si on travaille avec un pool de connexions dj ouvertes et disponibles pour les clients Lorsque le client na plus besoin de la connexion, il appelle la mthode close() qui la restitue au pool (la connexion nest pas ferme)

Comment obtenir un pool de connexions


On peut utiliser un des nombreux projets open source qui fournit le code pour grer un pool de connexion Le plus souvent un tel pool est fourni par une source de donnes de type javax.sql.DataSource

R. Grin

JDBC avanc

page 87

R. Grin

JDBC avanc

page 88

Source de donnes
Depuis JDBC 3 (mais dj en extension de JDBC 2), on peut obtenir une connexion dune instance de DataSource (une interface) au lieu de lobtenir de la classe DriverManager Une DataSource reprsente une base de donnes (mais elle peut aussi reprsenter un simple fichier texte) Tout driver JDBC 2 doit fournir une implmentation de DataSource ; oracle.jdbc.pool.OracleDataSource pour Oracle

R. Grin JDBC avanc page 89

Mthode getConnection

La mthode principale de DataSource est getConnection(String utilisateur, String motDePasse) qui renvoie une Connection (et peut lancer une SQLException) Si le nom et le mot de passe de lutilisateur ont t entrs dans la configuration de la source (par des setters par exemple), on peut aussi utiliser la mthode getConnection()
JDBC avanc page 90

R. Grin

15

Connexion dune DataSource


La connexion renvoye par getConnection peut tre une connexion ordinaire mais le plus souvent cest une connexion renvoye par un pool de connexions Lutilisation dune telle connexion se fait exactement comme une connexion ordinaire ; tout est transparent pour lutilisateur Une diffrence essentielle est que, lorsque le client appelle la mthode close de la connexion, celle-ci nest pas ferme mais remise dans le pool des connexions disponibles

R. Grin JDBC avanc page 91

Exemple dutilisation
DataSource ds = new OracleDataSource(); ((OracleDataSource)ds).setURL("jdbc:oracl e:thin:@euterpe.unice.fr:1521:INFO"); Connection conn = ds.getConnection("toto", "mdp"); // Le reste est identique au code qui // nutilise pas de source de donnes . . .

R. Grin

JDBC avanc

page 92

Obtenir une DataSource


Le plus souvent, la source de donnes est enregistre auprs dun registre JNDI On lobtient en donnant la cl du registre qui lui correspond :

Configurer une DataSource


Le plus souvent elle se configure par un fichier XML de configuration ; voir le manuel des logiciels que vous utilisez Exemple : fichier server.xml de Tomcat

DataSource source = (DataSource) new InitialContext() .lookup("MaSource");

Ce code ne peut fonctionner que dans un environnement dans lequel fonctionne un registre JNDI (serveur dapplications le plus souvent)
JDBC avanc page 93

Elle peut aussi se configurer par programmation ; voir la javadoc de la classe qui implmente DataSource

R. Grin

R. Grin

JDBC avanc

page 94

Exemple avec Tomcat : server.xml


<Context path="/BDTest" ...> <Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"/> <ResourceParams name="jdbc/TestBD"> <parameter> <name>factory</name> <value>org.apache.commons.dbcp.BasicDataSource Factory </value> </parameter>
R. Grin JDBC avanc page 95

Exemple avec Tomcat : server.xml


<! Le plus grand nombre de connexions dans le pool. Mettre 0 si pas de limite. --> <parameter> <name>maxActive</name> <value>100</value> </parameter>

etc

Voir la documentation Tomcat pour le reste du fichier server.xml

R. Grin

JDBC avanc

page 96

16

Exemple avec Tomcat : web.xml


<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC ...> <web-app> <description>TestDB</description> <resource-ref> <description>DB Connection</description> <res-ref-name>jdbc/TestBD</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> </web-app>
R. Grin JDBC avanc page 97

Exemple avec Tomcat code servlet


import javax.naming.*; import javax.sql.*; ... Context context = new InitialContext(); DataSource ds = (DataSource)ctx.lookup( "jdbc/TestBD" ); Connection conn = ds.getConnection( "toto", "mdp" ); ... finally { if( conn != null ) { conn.close(); } }
R. Grin JDBC avanc page 98

Limite des transactions JDBC


Elles ne permettent pas une transaction de couvrir plusieurs connexions des bases de donnes diffrentes Pourtant, lexistence de nombreuses bases de donnes hrites du pass conduisent parfois les applications dentreprise travailler avec des transactions qui couvrent plusieurs bases de donnes la fois

(Java Transaction API)

Transactions JTA

R. Grin

JDBC avanc

page 99

R. Grin

JDBC avanc

page 100

JTA
Cette API fournit les interfaces pour travailler avec des transactions distribues sur plusieurs bases de donnes, ou mme des ressources qui ne sont pas des bases de donnes, dune faon indpendante de limplmentation du gestionnaire de transactions Elle est utilise par les serveurs dapplications pour les transactions gres par le container

Transaction (1)
Interface du paquetage javax.transaction qui dcrit une transaction JTA Contient les mthodes commit(), rollback() La mthode setRollbackOnly() indique que la transaction ne pourra se terminer que par un rollback (utile quand le code ne gre pas directement le dbut et la fin de la transaction, par exemple quand on utilise un serveur dapplications)
R. Grin JDBC avanc page 102

R. Grin

JDBC avanc

page 101

17

Transaction (2)

Rfrences sur les JTA


Linterface contient aussi des mthodes pour associer (ou dsassocier) des ressources la transaction (le plus souvent des ressources lies des SGBDs) : enlistResource et delistResource Ces ressources pourront participer un commit 2 phases (commit pour les transactions distribues qui comprend 2 phases : la prparation et laccord des ressources, puis le commit effectif)
JDBC avanc page 103

JTA nest pas tudie en dtails dans ce cours 2 rfrences : http://java.sun.com/products/jta/ http://www.theserverside.com/articles/article.ts s?l=Nuts-and-Bolts-of-Transaction-Processing

R. Grin

R. Grin

JDBC avanc

page 104

18

Vous aimerez peut-être aussi