JDBC et objet
Transcription
JDBC et objet
Types de données de SQL3 JDBC et objet-relationnel Université de Nice - Sophia Antipolis JDBC supporte les types suivants de SQL3 qui sont des ouvertures vers le relationnelobjet : n ARRAY n types structurés définis par l’utilisateur n références vers des instances de types structurés Version 1.6.4 – 5/11/11 Richard Grin R. Grin Le type de collection VARRAY d’Oracle permet d'avoir des colonnes multivaluées Ils correspondent en Java à l’interface java.sql.Array Un Array enregistré dans une base de données peut être récupéré en Java sous la forme d’une instance de la classe Array par les méthodes suivantes de ResultSet n Array getArray(String nomColonne) n Array getArray(int numColonne) On récupère ainsi une référence qui peut servir à obtenir les valeurs de l’array Remarque : cette interface sert aussi pour les collections « tables imbriquées » d’Oracle (nested tables) R. Grin JDBC et relationnel-objet page 3 R. Grin Récupérer les éléments d’un Array On peut aussi récupérer un tableau Java entier par la méthode Object getArray() de Array R. Grin JDBC et relationnel-objet JDBC et relationnel-objet page 4 Enregistrer un Array void setArray(int i, Array x) de PreparedStatement permet d’enregistrer un Array ResultSet contient la méthode updateArray pour les resultSets modifiables PreparedStatement permet aussi d’enregistrer un tableau Java sous forme de Array avec la méthode setObject On peut ensuite récupérer dans un tableau Java des éléments d’un Array (pas nécessairement tous) par les méthodes de l’interface Array Object getArray(long debut, int longueur) ou en utilisant un ResultSet par ResultSet getResultSet() page 2 Récupérer un Array Array JDBC et relationnel-objet page 5 R. Grin JDBC et relationnel-objet page 6 1 Lire des éléments d’un Array Enregistrer un tableau String[] data; // remplit le tableau . . . PreparedStatement ps = conn.prepareStatement( "Update table1 " + "set tableau = ? where num = 5"); ps.setObject(1, data); R. Grin JDBC et relationnel-objet String[] data; Statement stmt = conn.createStatement(); ResultSet rset = stmt.executeQuery( "select * from table1 where num = 5"); if (rset.next()) { Array array = rset.getArray("tableau"); // ne récupère que les éléments 5 et 6 du tableau data = (String[])array.getArray(4, 2); for (int i = 0; i < data.length; i++) { System.out.println(data[i]); } } page 7 R. Grin Lire des éléments d’un Array On peut aussi utiliser un ResultSet pour lire les éléments d’un tableau déjà récupéré : R. Grin JDBC et relationnel-objet page 9 page 8 Type utilisateur String[] data; Statement stmt = conn.createStatement(); ResultSet rset = stmt.executeQuery("select . . ."); if (rset.next()) { Array array = rset.getArray("tableau"); // ne récupère que les éléments 5 et 6 du tableau ResultSet rsArray = array.getResultSet(4, 2); while (rsArray.next()) { System.out.println(rsArray.getString(1)); } } JDBC et relationnel-objet SQL 3 a introduit 2 formes de nouveaux types créés par l’utilisateur : n type « distinct », construit simplement à partir d’un type de base n type « structuré », plus complexe, construit sur le modèle d’une classe Java R. Grin JDBC et relationnel-objet page 10 Utilisation des types distinct et structuré dans la définition d’une table Type structuré Ces types rapprochent les SGBD relationnels du monde objet Ils sont créés par la commande SQL 3 « create type » : create type departement_type as object ( numDept integer, nomDept varchar(15), lieu varchar(20)) R. Grin JDBC et relationnel-objet page 11 create table emp ( matr matricule constraint pkEmp primary key, nomE varchar(15), . . . dept departement_type) R. Grin JDBC et relationnel-objet page 12 2 Utilisation des types structurés pour la persistance des classes Java Pour faciliter la persistance des classes Java 1. Créer un type structuré SQL de même structure que la classe 2. La classe Java doit implémenter l’interface java.sql.SQLData Utilisation des types structurés pour la persistance des classes Java La lecture et l’écriture dans une base de données des données d’une instance de la classe Java s’effectue alors en un seul appel de méthode getObject ou setObject 3. Indiquer le type structuré qui correspond à la classe Java R. Grin JDBC et relationnel-objet page 13 R. Grin Interface SQLData JDBC et relationnel-objet page 14 SQLInput et SQLOutput public interface SQLData { Flots qui contiennent des valeurs constituant une instance d’un type structuré (ou distinct) SQL Ils sont utilisés par le driver JDBC et le développeur ne les manipulent pas directement /** Lire une instance de la classe à partir * à partir des données de la base. */ void readSQL(SQLInput stream, String typeName) throws SQLException; /** Enregistre une instance de la classe * dans la base de données. */ void writeSQL(SQLOutput stream) throws SQL Exception; String getSQLTypeName() throws SQLException; } R. Grin JDBC et relationnel-objet page 15 R. Grin public class Dept implements SQLData { private int numDept; private String nomDept, lieu; // Type SQL qui correspond à la classe Dept private String nomTypeSQL; // Constructeurs et autres méthodes de Dept . . . JDBC et relationnel-objet page 16 Implémenter SQLData (2) Implémenter SQLData (1) R. Grin JDBC et relationnel-objet page 17 // Les 3 méthodes de l'interface SQLData public void readSQL(SQLInput flot, String type) throws SQLException { nomTypeSQL = type; numDept = flot.readInt(); nomDept = flot.readString(); L’ordre de lecture lieu = flot.readString(); (et d’écriture) } doit être celui donné dans la définition du type structuré R. Grin JDBC et relationnel-objet page 18 3 Correspondance entre les classes Java et les types structurés Implémenter SQLData (3) public void writeSQL(SQLOutput flot) throws SQLException { flot.writeInt(numDept); flot.writeString(nomDept); flot.writeString(lieu); } Pour faciliter l’enregistrement dans la base des données d’un type structuré, il faut indiquer le nom (complet, avec le paquetage) de la classe Java qui correspond à ce type On l’indique dans une Map utilisée en interne par la connexion : public String getSQLTypeName() { return nomTypeSQL ; } Map map = conn.getTypeMap(); map.put("toto.depart_type", p1.Dept.class); } R. Grin JDBC et relationnel-objet page 19 R. Grin Il est alors simple de lire et d’écrire des valeurs du type structuré : Statement stmt = conn.createStatement(); ResultSet rset = stmt.executeQuery( "SELECT * FROM EMP"); while (rset.next()) { Dept dept = (Dept)rset.getObject("DEPT"); System.out.println("Lieu du dept : " + dept.getLieu()); } R. Grin JDBC et relationnel-objet page 21 Dept dept = new Dept(…); . . . // Insertion d’un nouvel employé PreparedStatement ps = conn.createStatement( "INSERT INTO EMP" + "(matricule, …, dept)" + " VALUES (?, …, ?)"); ps.setInt(1, matricule); . . . // Une seule instruction pour le département ps.setObject(8, dept); R. Grin On peut aussi lire une valeur d'un type structuré sans devoir implémenter l’interface SQLData ni utiliser la Map qui fait la correspondance entre les classes Java et les types structurés Dans ce cas, on doit lire colonne par colonne en utilisant l’interface java.sql.Struct JDBC et relationnel-objet JDBC et relationnel-objet page 22 Lecture sans utiliser la Map Sans utilisation de la Map R. Grin page 20 Écriture d’un type structuré Lecture d’un type structuré JDBC et relationnel-objet page 23 Statement stmt = conn.createStatement(); ResultSet rset = stmt.executeQuery("SELECT * FROM emp"); while (rset.next()) { Struct struct = (Struct)rset.getObject("DEPT"); Object[] valeurs = struct.getAttributes(); System.out.println("Lieu du dept : " + valeurs[2]); } 3ème champ R. Grin JDBC et relationnel-objet page 24 4 Références en SQL 3 Nouveau type de table SQL 3 Le processus de normalisation conduit à éclater les données en plusieurs tables Lorsque l’on veut retrouver des informations, on doit alors souvent effectuer des jointures, par exemple pour savoir dans quelle ville les employés travaillent En SQL3 on peut le faire sans que cela ne nécessite de jointure En effet, SQL3 permet de manipuler les références à une information R. Grin JDBC et relationnel-objet page 25 Si on veut pouvoir référencer les lignes d'une table T dans une autre table, il faut créer cette table T à partir d'un type structuré Par exemple, à partir du type structuré dept_type, on peut créer la table dept : create table dept of departement_type ( constraint pk_dept primary key dept) R. Grin Utilisation des références dans la définition d’une table create table emp ( matr matricule constraint pkEmp primary key, nomE varchar(15), . . . dept ref departement_type ) R. Grin JDBC et relationnel-objet page 27 R. Grin JDBC et relationnel-objet page 29 page 26 Récupération d’une référence On peut récupérer une référence grâce à la méthode getRef Si on a une référence, il est possible de l’utiliser pour interroger une table qui contient une référence du même type en utilisant setRef R. Grin Récupération d’une référence java.sql.Ref refDept; Statement stmt = conn.createStatement(); ResultSet rset1 = stmt.executeQuery( "SELECT dept from emp " + "where matricule = 105"); if (rset1.next()) { refDept = rset1.getRef("dept"); if (! rset1.wasNull()) { ... JDBC et relationnel-objet JDBC et relationnel-objet page 28 Utilisation d’une référence java.sql.Ref refDept; ... // Récupère une valeur pour refDept PreparedStatement ps = conn.prepareStatement( "SELECT * FROM emp" + " WHERE REF(dept) = ?"); ps.setRef(1, refDept); ResultSet rset2 = ps.executeQuery(); while (rset2.next()) { System.out.println(rset2.getString("nom") } R. Grin JDBC et relationnel-objet page 30 5 Utilisation d’une référence (2) Si on a une référence, le moyen le plus simple pour récupérer l’objet référencé est d’utiliser la méthode getObject() de Ref R. Grin JDBC et relationnel-objet page 31 deref Il est souvent plus simple d’utiliser une requête SQL modifiée pour travailler directement avec l’objet référencé Rappel : n deref(référence) permet d’obtenir un objet dont on a la référence n La notation pointée (ou la variante syntaxique « -> » selon les SGBD) permet de récupérer facilement les valeurs d’un objet pointé : dept.lieu R. Grin JDBC et relationnel-objet page 32 Exemple d’utilisation d’une référence ResultSet rset = stmt.executeQuery("SELECT dept FROM employe"); while (rset.next()) { Ref refDept = rset.getRef("dept"); if(refDept != null) { Struct struct = (Struct)refDept.getObject(); Object[] val = struct3.getAttributes(); String lieuDept = (String)val[2]; } ... R. Grin JDBC et relationnel-objet page 33 6