Académique Documents
Professionnel Documents
Culture Documents
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
R. Grin
JDBC avanc
page 6
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
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
R. Grin
JDBC avanc
page 11
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
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
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
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
R. Grin
JDBC avanc
page 21
R. Grin
JDBC avanc
page 22
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
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
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
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
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
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
R. Grin
JDBC avanc
page 37
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();
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 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() } }
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
R. Grin
JDBC avanc
page 51
R. Grin
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
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
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
10
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
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
11
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
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
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
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
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
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
JDBC avanc
page 76
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
13
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
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 84
14
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)
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
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
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
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
etc
R. Grin
JDBC avanc
page 96
16
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)
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