Cours informatique : Bases de données orientéesobjets
1. Introduction
2. Le problème
3. Les différentes solutions
4. La sérialisation Java
5. La sérialisation Java : exemple
6. Les SGBD
7. Acronymes
8. Historique des SGBD (1)
9. Historique des SGBD (2)
10. Historique des SGBD (3)
11. Historique des SGBD (4)
12. Modèles de données
13. Architecture à trois niveaux
14. Langages de définition et de manipulation de données
15. Stockage de données (1)
16. Stockage de données (2)
17. Les bases de données relationnelles
18. Tables relationnelles
19. Clés primaires et clés étrangères
20. Tables entités et tables relations
21. Domaines et intégrité référentielle
22. Langage de manipulation de données
23. Langage de définition de données
24. Les bases de données objets
25. SGBDO: modèle de données
26. Identifiants d'objets
27. Attributs
28. Attributs litéraux
29. Attributs références
30. Attributs collections et tableaux
31. Attributs dérivés
32. Relations
33. Intégrité référentielle
34. EyeDB: généralités
35. Introduction
36. Architecture de EyeDB
37. Le modèle objet
38. Le langage ODL
39. Le langage OQL
40. Les bindings langages
41. EyeDB: outils
42. eyedbctl : gestion du serveur
43. eyedbadmin : outil général d'administration
44. eyedbadmin database : administration des bases de données
45. eyedbadmin user : administration des utilisateurs
46. eyedbodl : interpréteur du langage de définition de données
47. eyedboql : interpréteur du langage de manipulation de données
48. EyeDB: le langage ODL
49. Introduction
50. Classes
51. Types de base
52. Types énumérés
53. Tableaux
54. Litéraux et références
55. Litéraux
56. Références
57. Collections
58. Héritage
59. Relations
60. Intégrité référentielle
61. EyeDB: le langage OQL
62. OQL
63. L'interpréteur OQL
64. Affectation et variables
65. Expressions
66. Opérateur de déréférencement de tableau
67. Schéma exemple
68. Création d'objets
69. Collections
70. Path expressions
71. Destruction d'objets
72. Requêtes
73. Requêtes : exemples
74. EyeDB: les interfaces de programmation Java et C++
75. Principes
76. Interface Java
77. Exemple de code Java
78. Hibernate, un framework de mapping objet-relationnel
79. Hibernate, introduction
80. Mise en oeuvre de Hibernate
81. Configuration
82. Les propriétés de configuration
83. Implémentation d'une classe persistante
84. Fichier de mapping
85. Les classes Session et SessionFactory
86. Transactions
87. Création d'objets persistants
88. Chargement d'objets
89. Mise à jour d'objets persistants
90. Destruction d'objets
91. Collections
92. Gestion des relations
93. Relations : exemple one-to-many
94. Relations : exemple many-to-many
95. Héritage
96. Héritage: exemples
97. Langage de requêtes HQL
98. HQL: exemples
99. HQL: exécution d'une requête
100. Travaux dirigés
101. EyeDB : compilation et installation
102. EyeDB : administration basique
103. L'application exemple
104. EyeDB : définition d'un schéma ODL
105. EyeDB : utilisation du langage OQL
106. EyeDB : utilisation du binding Java
107. Hibernate
_______________________
Cours ESIEA
Auteur : François Déchelle
Version 1.3
2. Le problème
Contexte:- rôle prépondérant des technologies et des langages objets (C++, Java, Python, Ruby, PHP5...) dans le développement d'applications
- besoin de manipulations de données persistantes (ex: contribuables/déclarations pour la télédéclaration des impôts, produits/commandes pour un site de vente en ligne...
- besoins classiquement couverts par les bases de données relationnelles
Problème: rendre les objets persistants, c.à.d. de durée de vie supérieure à la durée des programmes manipulant les données
3. Les différentes solutions
Plusieurs solutions de persistance objet existent:- sérialisation
- mapping objet-relationnel
- bases de données objets
- bases XML
Le choix d'une solution dépend des besoins applicatifs.
4. La sérialisation Java
La sérialisation est implémentée dans les classes java.io.ObjetInputStream
et java.io.ObjetOutputStream
:
- le format de sauvegarde est indépendant de la plateforme
- le mécanisme de sérialisation va prendre en compte les objets contenus dans un objet (attributs de type objet) et va sauvegarder récursivement ces objets, en gérant les cycles
- un objet peut être lu ou écrit s'il est instance d'une classe qui implémente l'interface
Serializable
5. La sérialisation Java : exemple
Example 1. Ecriture d'un objetFileOutputStream fs = null; ObjectOutputStream os = null; Test t = new Test(); try { fs = new FileOutputStream("base.ser"); os = new ObjectOutputStream(fs); os.writeObject( t); os.close(); } catch (Exception e) { System.err.println( e); }
Example 2. Lecture d'un objet
FileInputStream fs = null; ObjectInputStream is = null; Test t; try { fs = new FileInputStream("base.ser"); is = new ObjectInputStream(fs); t = (Test)is.readObject(); System.out.println( s); is.close(); } catch (Exception e) { System.err.println( e); }
Inconvénients:
- inefficace: accès séquentiel, pas d'accès indexé
- peu robuste: un crash peut corrompre définitivement les données
- pas d'accès concurrent: une seule application peut accéder au fichier
6. Les SGBD
SGBD: Système de Gestion de Bases de Données
Un SGDB permet de gérer des données structurées et persistantes:
- structurées: doit offrir un système de typage
- persistantes: dont la durée de vie est supérieure à la durée des programmes manipulant les données
de façon intègre, fiable, concurrente et efficace:
- intègre : vue cohérente en dépit des accès concurrents
- fiable : récupération des données en cas de crash logiciel, système ou disque
- concurrente : gérer les accès multi-utilisateurs notamment en cas de modification
- efficace : indexation, langage de requêtes
7. Acronymes
- BD: base de données
- DB: database
- SGBD: système de gestion de base de données
- DBMS: database management system
- R: relationnel / relational
- E-R: entité-relation / entity-relation
- O: objet / object
- OO: orienté objet / object oriented
- OR: objet-relationnel
- RO: relational-object
- SGBDR, SGBDOO, SGBDO, SGBDOR
- RDBMS, OODBMS, ODBMS, RODBMS
8. Historique des SGBD (1)
Les fichiers indexés:
- des enregistrements de taille fixe comprennant des données de différents types
- la sauvegarde des enregistrements dans des fichiers disques et la capacité à traiter plus de données que la mémoire centrale ne peut en contenir et leur rangement dans un espace persistant
- des index, gérés en tables de hashage ou B-trees permettant de localiser rapidement des enregistrements
- un verrouillage des fichiers et des enregistrements pour contrôler les accès concurrents.
9. Historique des SGBD (2)
Le modèle hiérarchique et réseau (1970):
- identifiants ou adresses d'enregistrements et des liens pour accéder rapidement aux données en les interconnectant. Ces liens permettent de bâtir des structures d'enregistrement hiérarchiques ou réseaux
- de multiples fichiers d'index ouverts simultanément et considérés comme une base unique grâce aux interconnections d'enregistrements
- des contraintes de protection pour limiter l'accès des enregistrements aux utilisateurs ou aux programme autorisés
- des transactions et un système de recouvrement pour récuperer automatiquement la base en cas de panne, détecter les verrous mortels et maintenir la cohérence du SGBD lorsque plusieurs utilisateurs y accèdent.
10. Historique des SGBD (3)
Les bases de données relationnelles (1980):
- Un langage pour la définition et la manipulation des données et des outils pour générer des applications ou des écrans
- L'indépendance des données: la possibilité de modifier la manière de stocker physiquement les données sans conséquence sur les programmes d'applications
- Contribution majeure: simplicité comparativement à des modèles plus anciens.
11. Historique des SGBD (4)
Les bases de données objets (1990):
- un modèle de données basé sur les paradigmes de la programmation orienté objet
12. Modèles de données
Une base de données contient des données structurées selon un schéma, méta-données qui décrivent la structuration des données.
Comme tout langage de programmation, les SGBD possèdent des contraintes sur les types de données et les schémas autorisés. L'ensemble des contraintes sur le système de typage s'appelle le modèle de données, qui spécifie les données et les opérations associées.
13. Architecture à trois niveaux
Un SGBD possède trois niveaux d'abstraction:
- niveau conceptuel: modélisation des données plus ou moins indépendamment du SGBD (R ou O): conception UML
- niveau logique: modélisation des données, y compris le type des enregistrements et des champs et leurs relations: create table
- niveau physique: organisation des données sur un support physique, ordre et encodage des valeurs des champs, ordre et taille des enregistrements et méthodes d'accès disponibles (liens et index)
14. Langages de définition et de manipulation de données
Un langage de définition de données (LDD ou DDL, data definition language), permet de décrire le modèle de données d'un SGBD.
Un langage de manipulation de données (LMD ou DML, data manipulation language), permet de manipuler les données:
- création, destruction, modification, lecture
- requêtes
- gérer la persistance des données (Persistency)
- offrir un mécanisme pour l'atomicité (Atomicity)
- offrir des mécanismes d'intégrité aux données (Consistency) : la base de données doit permettre de donner une vue cohérente d'un ensemble de données tout au long d'une transaction utilisateur indépendamment des accès en lecture/écriture des autres utilisateurs
- gérer la concurrence aux données (Isolation) : mécanisme de verrous. Doit permettre de gérer les conflits possibles lors de transactions concurrentes: transactions qui se déroulent en même temps sur des données identiques
- récupérer les données en cas de crash logiciel, système d'exploitation ou disque (Durability)
- mécanisme d'indexation des données en hash tables ou B-trees
- système transactionnel: Atomicity, Consistency, Isolation[, Durability]
- système de reprise sur panne: Durability
- l'attribut
DocID
de la tableDocument
est une clé primaire - l'attribut
DocID
de la tableChapitre
est une clé étrangère20. Tables entités et tables relations
On distingue deux types de tables:
- les tables possédant des clés primaires sont appelées tables d'entité; elles représentent les types d'objets
- les autres tables sont appelées tables de relation; elles représentent les relations entre les objets à l'aide de clés étrangères
Example 5. Exemple de tables entités et relations:
Relation Personne
Relation AuteurNom AutID Eric Viara 1 François Déchelle 2 DocId AutID 4382 1 4382 2 7391 1 7391 2 8439 1 21. Domaines et intégrité référentielle
Le domaine est un type d'attribut, définissant l'ensemble des valeurs permises à l'attribut. Les domaines permettent de vérifier la cohérence d'opérations.
L'intégrité référentielle est un ensemble de contraintes sur les clés étrangères utilisées dans la base de données:
- la valeur d'une clé étrangère doit être une clé primaire existante
- lorsqu'un enregistrement est détruit, les enregistrements référençant sa clé primaire à travers des clés étrangères doivent être automatiquement invalidés
- regroupement ou agrégation: regroupement en TAD (Type Abstrait de Données) ou classe. La classe est l'abstraction fondamentale permettant de modéliser des caractéristiques et des comportements communs à plusieurs objets.
- identité d'objet: chaque objet possède une identité unique indépendante des valeurs contenues. Le modèle R repose sur des valeurs: une entité (ou objet) est identifiée à l'aide de sa clé primaire. Un système reposant sur les identités permet d'établir des références entre objets grâce à un numéro unique généré en interne, appelé OID, indépendant de la valeur de sa clé primaire, si il en existe une.
- tous les travaux ont reconnus les limitations imposées par les clés primaires et par les modèles reposant sur la notion de valeur. Ils ont introduit le concept d'identifiant d'objet, connu sous le nom d'OID (Object IDentifier)
- les clés primaires obligent le programmeur soit à générer ses propres identifiants uniques, soit à utiliser des noms significatifs
- les OIDs prennent toute leur importance dès qu'un objet de la base est référencé par un autre objet ou un programme d'application
- littéral simple: int, string, flottant
- littéral étendu: date ou littéral défini par l'utilisateur: ce sont en fait des objets sans OID
- référence: référence à d'autres objets
- collection: set, bag, list (et array)
- tableau: multi dimensionnel
- attribut dérivé ou virtuel: getXx()
- littéral simple ou basique: int, string, flottant
- les littéraux structurés builtin: Date, Time
- les littéraux structurés utilisateur
- ce sont les équivalents des pointeurs dans les langages de programmation ou des clés étrangères dans les systèmes R
- contrairement aux pointeurs, la référence est persistante
- si l'objet référencé est détruit, l'attribut référence est automatiquement invalidé
- une relation (1-1) par l'ajout d'un attribut référence à chaque type:
class A { attribute B b; }; class B { attribute A a; };
- une relation (N-1) par l'ajout d'un attribut référence à A et d'un attribut collection de références à B:
class A { attribute B b; }; class B { attribute set<A> set_of_a; };
- une relation (N-M) par l'ajout d'un attribut collection de références à A et d'un attribut collection de références à B:
class A { attribute set<B> set_of_b; }; class B { attribute set<A> set_of_a; };
- aucune vérification d'intégrité: la référence à un objet de type incorrect, inexistant ou détruit est possible (C ou C++)
- validation des références: le système détermine automatiquement le moment où l'objet peut être détruit (garbage collector) (Java, Python...)
- intégrité des relations: le système permet de détruire et de modifier les objets et maintient automatiquement la validité des relations entre objets (la majorité des SGBDO)
- sémantique de références personnalisées: la sémantique d'intégrité référentielle peut être définie par l'utilisateur
- un modèle objet avancé (héritage, collections, tableaux, méthodes, triggers, contraintes)
- un langage de définition de données basé sur ODMG ODL
- un langage de manipulation de données basé sur ODMG OQL
- des interfaces de programmation en C++ et Java
- storage manager: gestion des fichiers, gestion des index
- object system: classes, oids, collections
- schema manager: ODL
- query manager: OQL
- bindings: C++, Java
- Linux, 32 et 64 bits
- Solaris
- Mac OS X
- héritage simple
- collections: bag, list, set, array
- tableaux multi-dimensionnels
- méthodes OQL ou externes
- triggers
- contraintes
- définir le schéma d'une base
- représenter textuellement le schéma d'une base existante
- générer du code pour un langage objet donné (Java, C++) à partir du schéma de la base
- langage entièrement interprété
- définition de variables
- opérateurs
- structures de contrôle
- création, destruction d'objets
- requêtes
- une bibliothèque client (C++, Java) supportant protocole client/serveur, connexion, accès au schéma...
- un mécanisme de traduction du schéma ODL vers des langages objets (C++, Java, Python, PHP5, Ruby...) permettant d'accéder aux fonctionnalités de persistance
22. Langage de manipulation de données
La quasi totalité des SGBDR proposent le langage SQL comme langage de manipulation de données
Example 6. Exemple de requêtes SQL:
SELECT TITRE, DATE FROM DOCUMENT WHERE DATE > 2000;
SELECT CHAPITRE.TITRE FROM CHAPITRE, DOCUMENT, AUTEUR WHERE CHAPITRE.DOCID = DOCUMENT.DOCID AND DOCUMENT.AUTID = AUTEUR.AUTID AND AUTEUR.NOM = "Eric Viara";
23. Langage de définition de données
Le langage SQL fournit un langage de définition de données (LDD), permettant de définir le schéma des données.
Example 7. Exemple de requêtes SQL de création de table:
CREATE TABLE DOCUMENT ( DOCID INTEGER, TITRE CHAR(40), REVISION DATE);
24. Les bases de données objets
25. SGBDO: modèle de données
Les SGBDO possèdent deux caractéristiques essentielles:
26. Identifiants d'objets
Le concept d'identifiants d'objets générés par système remonte à 1974 (Abrial) qui les appela suppléants:
27. Attributs
Les SGBDO sont plus souples que le modèle R sur les attributs autorisés dans un objet (ou enregistrement):
28. Attributs litéraux
Un litéral n'a pas d'identifiant
Les types de littéraux sont :
Example 8. Exemple de litéraux:
struct Complex { int re; int im; }
Les attributs litéraux sont stockés par valeur puisqu'il n'ont pas d'identifiants.
29. Attributs références
On utilise les attributs références (ou associations) pour représenter des relations entre objets
Contrairement aux clés étrangéres, les attributs références ne sont pas associés à des valeurs visibles par l'utilisateur. Si toutes les valeurs de l'objet référencé sont modifiées, l'attribut référence désigne toujours le même objet.
30. Attributs collections et tableaux
Les SGBDO proposent des collections ordonnées (LIST, ARRAY) et non ordonnées (SET, BAG). Les collections contiennent soit des valeurs littérales simples soit des références (qui peuvent d'ailleurs référencer d'autres collections).
Un attribut de type collection peut-être soit une collection litérale (sans OID et attaché à l'objet) soit une référence vers une collection.
31. Attributs dérivés
Au lieu de stocker explicitement une valeur d'attribut, il est possible de la définir de manière procédurale, en spécifiant une procédure à exécuter dès que la valeur est consultée ou affectée.
Example 9.
class Person { attribute date birthdate; virtual attribute int age; }
Un attribut virtuel est lié à deux procédures:
int age(void)
etvoid age(int)
pour la mise à jour.Aucune implémentation actuelle des SGBDO ne permet la mise à jour des attributs virtuels.
32. Relations
Dans le modèle O, on représente les relations au moyen des attributs complexes décrits précédemment: références et collection de références.
Le choix de la représentation dépend à la fois de la multiplicité et du degré de la relation
Les relations binaires entre deux types A et B sont représentées de la manière suivante:
33. Intégrité référentiellev
Pour maintenir la cohérence des relations binaires (1-1), (1-N) ou (N-M), les attributs doivent être synchronisés: si un objet est détruit ou si ses relations changent, les références des objets en relation avec cet objet doivent être mises à jour
Plusieurs niveaux d'intégrité référentielle:
34. EyeDB: généralités
35. Introduction
EyeDB est un SGBDO basé sur la spécification ODMG, développé par la société SYSRA (Eric Viara) depuis 1994.
EyeDB propose:
EyeDB est un logiciel open source, distribué sous licence LGPL
36. Architecture de EyeDB
EyeDB est basé sur une architecture client/serveur classique dans les SGBD, comprenant les modules suivants:
EyeDB est écrit en C++ et fonctionne sur les architectures suivantes:
37. Le modèle objet
Le modèle objet de EyeDB est très inspiré du modèle objet de Smalltalk ou de Java:
Le système objet de EyeDB est réflexif (représentation des concepts du système, classe, instance... par des objets)
38. Le langage ODL
Le langage ODL est le langage de définition de données (LDD) de EyeDB.
ODL est basé sur la spécification ODMG
ODL est utilisé pour:
39. Le langage OQL
Le langage OQL est le langage de manipulation de données (LMD) de EyeDB
OQL est basé sur la spécification ODMG
Quelques caractéristiques/fonctionnalités de OQL:
40. Les bindings langages
Le lien entre EyeDB et les langages objets est fait par l'intermédiaire de bindings, reposant sur:
15. Stockage de données (1)
La couche stockage des données propose un certain nombre de services:
16. Stockage de données (2)
Propriétés "ACID" (Atomicity, Consistency, Isolation, Durability):
Les SGBD R et O proposent des stockage des données similaires.
17. Les bases de données relationnelles
18. Tables relationnelles
Le modèle relationnel est un modèle simple, basé sur l'algèbre des relations.
La structure de données est la table, comprenant des lignes et des colonnes ne contenant que des données de type simple (entier, string, date...).
Example 3. Exemple de tables relationnelles:
Relation Document
Relation ChapitreDocID Titre Revision 4382 EyeDB : Getting Started 2005 7391 EyeDB : Java Programming Manual 2006 8439 EyeDB : ODL Reference Manual 2006 Numero Titre DocID 1 Introduction 4382 2 Installing EyeDB 4382 3 Starting EyeDB server 4382 ... ... ... 1 Introduction 7391 2 Java classes summary 7391 3 Java API 7391 ... ... ... 19. Clés primaires et clés étrangères
Une clé primaire est un attribut ou un groupe d'attributs dont la valeur est unique pour les colonnes de la table.
Une clé étrangère est un attribut ou un groupe d'attributs dont la valeur est la clé primaire d'une autre table. Une clé étrangère est une référence à un objet.
Example 4. Exemple de clés:
Les classes persistantes ne sont pas fournies par le code applicatif, mais générées
Les bindings EyeDB permettent d'ajouter un mécanisme de persistance dans les langages objets courants (Java, C++, PHP5, Ruby, Python...)
41. EyeDB: outils
42. eyedbctl : gestion du serveur
eyedbctl --help Program Options: start [-f] Launch the server. Set -f to force launch stop [-f] Stop the server. Set -f to force stop status Display status on the running server
Example 10.
eyedbctl start Starting EyeDB Server Version V2.8.7 Compiled Aug 5 2008 14:22:55 Architecture i686-pc-linux-gnu Program Pid 11499
43. eyedbadmin : outil général d'administration
La commande eyedbadmin permet d'administrer:
- les bases de données: création, destruction, liste, droits d'accès...
- les utilisateurs: création, destruction, liste, droits...
- les index: création, destruction, liste, optimisation...
- ...
44. eyedbadmin database : administration des bases de données
eyedbadmin database help eyedbadmin database usage: eyedbadmin database --help eyedbadmin database COMMAND OPTIONS where COMMAND is one of the following: create delete list move copy rename defaccess export import
Example 11.
eyedbadmin database create foo eyedbadmin database list Database Name person_j Database Identifier 2 Database File /home/francois/projects/eyedb/install/var/lib/eyedb/db/person_j.dbs ...
45. eyedbadmin user : administration des utilisateurs
eyedbadmin user eyedbadmin user usage: eyedbadmin user --help eyedbadmin user COMMAND OPTIONS where COMMAND is one of the following: add delete list sysaccess dbaccess passwd
Example 12.
eyedbadmin user list name : "toto" sysaccess : DB_CREATE_SYSACCESS_MODE dbaccess : (dbname : "zzz", access : ADMIN_DBACCESS_MODE) name : "francois" [strict unix user] sysaccess : SUPERUSER_SYSACCESS_MODE dbaccess : (dbname : "person_j", access : ADMIN_DBACCESS_MODE) (dbname : "person_c", access : ADMIN_DBACCESS_MODE) (dbname : "person_g", access : ADMIN_DBACCESS_MODE) (dbname : "foo", access : ADMIN_DBACCESS_MODE)
46. eyedbodl : interpréteur du langage de définition de données
eyedbodl eyedbodl: one and only one major option must be specified: --gencode=C++ --gencode=Java --gencode=ODL --update|-u --diff --checkfile --help
Example 13.
eyedbodl -u -d eee /var/tmp/t.odl Updating 't' schema in database eee... Adding class C1 Adding class C Adding class A Adding class B Done
47. eyedboql : interpréteur du langage de manipulation de données
eyedboql -h usage: eyedboql [-d NAME|--database=NAME] [-r|--read] [-w|--read-write] [-s|--strict-read] [-l|--local] [-c COMMAND|--command=COMMAND] [-p|--print] [--full] [--commit] [-i|--interact] [-e|--echo] [--admin] [-h|--help] [FILE..]
Example 14.
eyedboql -r -d eee -p -c 'select schema' = bag(2570.7.1557:oid, 2578.7.563199:oid, 2612.7.38164:oid, 2620.7.804024:oid) struct C1 {2570.7.1557:oid} : struct : agregat : instance : object { attribute int32 i; }; struct C {2578.7.563199:oid} : struct : agregat : instance : object { attribute set<C1> s; attribute bag<C1> b; attribute array<C1> a; attribute list<C1> l; }; struct A {2612.7.38164:oid} : struct : agregat : instance : object { attribute string sa; attribute B* b; }; struct B {2620.7.804024:oid} : struct : agregat : instance : object { attribute string sb; attribute A* a; };
48. EyeDB: le langage ODL
49. Introduction
Le langage ODL est un langage de spécification de types basé sur la spécification ODL ODMG.
ODL est un Langage de Définition de Données (LDD)
ODL permet de définir les caractéristiques des types (classes): attributs, relations, méthodes, contraintes, index, triggers.
ODL sert:
- à spécifier le schéma de la base de données une fois cette base créée
- à mettre à jour le schéma d'une base de données existante
- à générer le code nécessaire pour l'écriture d'une application cliente dans un langage de programmation orienté objet (Java, C++, Python, PHP...)
ODL est "interprété" par l'outil eyedbodl
50. Classes
Le concept de base de ODL est la classe, qui modélise un ensemble d'objets ayant même caractéristiques (attributs) et comportements (méthodes).
Une classe est spécifiée par:
- nom
- attributs, le type des attributs pouvant être : types de base, tableaux, objets, références, collections
- méthodes, définies en C++ ou en OQL
- relations, avec spécification de l'intégrité référentielle
- triggers
- index
51. Types de base
Les types de base de ODL sont:
Type Taille byte 1-byte integer char 1-byte character short 2-byte integer int 4-byte integer long 8-byte integer double 8-byte floating point oid 8-byte internal object identifier enum 4-byte integer Example 15. Exemple de classe ODL, types de base:
class C { attribute byte b; attribute char c; attribute int i; attribute double d; attribute oid o; };
Le mot-cle
attribute
est optionnel52. Types énumérés
ODL fournit les types énumérés à la façon du C++, dénotés par un ensemble de symboles associés à des valeurs entières.
Example 16. Exemple de classe ODL, types énumérés:
enum E1 { A, // A == 0 B, // B == 1 C // C == 2 }; enum E2 { D = 3, // D == 3 E, // E == 4 F = 100, // F == 100 G, // G == 101 H // H == 102 }; class C { E1 e1; E2 e2; };
53. Tableaux
ODL permet de définir des attributs de type tableaux multi-dimensionnels, de taille fixe ou variable, dont les éléments sont de types quelconques.
Example 17. Exemple de classe ODL, tableaux:
class C { attribute byte b_a[4]; // fixed length mono-dimensionnal array attribute char str[]; // variable size mono-dimensionnal array attribute int i_a[3][4][8]; // multi-dimensionnal fixed size array attribute long l_a[][4][8]; // multi-dimensionnal variable size array };
Un type particulier de tableau, le tableau de caractères, peut être noté
string
Example 18. Exemple de classe ODL, tableaux:
class C { attribute string s; // <=> char s[] (unlimited size string) attribute string<32> bs; // <=> char bs[32] (bounded string) };
54. Litéraux et références
Un objet possède toujours un identifiant unique appelé OID, valeur unique dans un ensemble de bases de données
Il existe deux types d'attributs:
- un attribut litéral est un attribut entièrement inclus dans une instance de la classe et ne possède pas d'OID
- un attribut objet est une référence à un autre objet possédant un OID
55. Litéraux
Example 19. Exemple de classe ODL, litéraux:
class C1 { attribute int i; }; class C { attribute C1 l_c1; // literal attribute included in C };
Si
c
est une instance deC
:c
inclut un litéral de typeC1
via l'attributl_c1
- si
c
est détruit, l'attributl_c1
est détruit en même temps
56. Références
Example 20. Exemple de classe ODL, références:
class C1 { attribute int i; }; class C { attribute C1 *o_c1; // object attribute referenced by C (or &oc1_1) };
Si
c
est une instance deC
:c
référence un objet de typeC1
via l'attributo_c1
- si
c
est détruit, l'objet référencé paro_c1
n'est pas détruit
57. Collections
EyeDB supporte 4 types de collections:
set
,bag
,array
etlist
:set
: collection non ordonnée d'éléments de même type, sans duplicationbag
: collection non ordonnée d'éléments de même type, avec duplicationarray
: collection ordonnée d'éléments de même type, avec duplicationlist
:: collection ordonnée d'éléments de même type, avec duplication, permettant insertion et destruction efficaces
Un élément peut être d'un type quelconque, litéral ou objet.
Une collection peut être un litéral ou un objet.
Example 21. Exemple de classe ODL, collections:
class C { attribute set<C1> l_c1_lset; // literal set of C1 literals attribute bag<C1 *> o_c1_lbag; // literal bag of C1 objects attribute array<C1> *l_c1_oarr; // object array of C1 literals attribute list<C1 *> *o_c1_olist; // object list of C1 objects
58. Héritage
EyeDB supporte l'héritage simple spécifié par le mot-clé
extends
Example 22. Exemple de classe ODL, héritage:
class C1 { attribute string c1; }; class C2 extends C1 { attribute string c2; };
Un objet de la classe
C2
incluera les deux attributsc1
etc2
.59. Relations
EyeDB support les relations 1-1, 1-n et n-m.
Une relation entre une classe
A
et une classeB
est réalisée par des attributs des deux classes ayant les types suivant, en fonction de la cardinalité de la relation:- 1-1:
A
contient un attribut de typeB *
etB
contient un attribut de typeA *
- 1-n:
A
contient un attribut de typecollection<B *>
(collection est de typeset
oubag
) etB
contient un attribut de typeA *
- n-m:
A
contient un attribut de typecollection<B *>
etB
contient un attribut de typecollection<A *>
Example 23. Exemple de classe ODL, relations:
class A { attribute string sa; attribute B *b; }; class B { attribute string sb; attribute A *a; };
Dans ce cas, EyeDB maintient seulement une intégrité référentielle partielle: si un objet de
A
est détruit, l'attributa
référencera toujours l'objet détruit.60. Intégrité référentielle
EyeDB peut maintenir l'intégrité référentielle en utilisant la directive
inverse
de ODL.Example 24. Exemple de classe ODL, intégrité référentielle:
class A { attribute string sa; relationship B *b inverse B::a; // or inverse a }; class B { attribute string sb; relationship A *a inverse A::b; // or inverse b };
Dans ce cas, si un objet
B
référencé par un objetA
via l'attributb
est détruit, l'attributb
sera positionné àNULL
.61. EyeDB: le langage OQL
62. OQL
OQL (Object Query Language) est le Langage de Manipulation de Données de EyeDB
EyeDB OQL est en partie conforme à la spécification OQL de ODMG
OQL permet:
- de créer, détruire, modifier des objets
- de faire des requêtes sur la base
- d'écrire des méthodes
OQL est un langage interprété complet, fournissant structures de contrôle, opérateurs, fonctions...
63. L'interpréteur OQL
L'interpréteur OQL fonctionne de manière similaire à l'interpréteur Python.
Il est lancé par la commande eyedboql:
eyedboql -w -d cours
Example 25. OQL: l'interpréteur
? 1+2; = 3 ? "hello " + "world"; = "hello world" ? set(1,2,3); = set(1, 2, 3) ? set(1,2,3)+set(4, 5, 6); = set(1, 2, 3, 4, 5, 6)
64. Affectation et variables
L'opérateur d'affection de OQL est noté
:=
L'opérande de gauche peut être:
- une variable
- une path-expression (voir plus loin)
Si l'opérande de gauche est une path-expression, OQL vérifie la validité des types.
Example 26. OQL: variables et affectation
? x := 1; = 1 ? y := 2; = 2 ? z := x + y; = 3 ? a := set( 1, 2, 3); = set(1, 2, 3) ? b := set( 4, 5, 6); = set(4, 5, 6) ? c := a + b; = set(1, 2, 3, 4, 5, 6)
Les opérateurs d'affectation de C (+=, -=...) sont disponibles
Example 27. OQL: opérateurs d'affectation
? c += set( 7, 8, 9); = set(1, 2, 3, 4, 5, 6, 7, 8, 9)
65. Expressions
OQL fournit des expressions arithmétiques et logiques acceptant comme opérandes tous les types du langage (types de base, collections, objets).
Les expressions arithmétiques sont construites à l'aide des opérateurs standard de C (+ * << % ...)
Les expressions logiques sont construites à l'aide des opérateurs standard de C (!= <...) et des opérateurs de pattern-matching sur les expressions régulières
Example 28. OQL: opérateurs de pattern-matching
? s := "Paris"; = "Paris" ? s ~ "P*"; = true ? s ~ "^Pa.is$"; = true
66. Opérateur de déréférencement de tableau
L'opérateur de déréférencement de tableau
[]
permet d'accéder à un élément d'un tableau ou d'une collection ordonnéeExample 29. OQL: opérateur de déréférencement de tableau
? t := list( "a", "b", "c"); = list("a", "b", "c") ? t[0]; = "a" ? t[4]; near line 19: 't[4]' => oql error: operator [] 't[4]' : out of bounds value, 4, for list. ?
L'opérateur de déréférencement de tableau
[:]
permet d'accéder à une "tranche" de la collectionExample 30. OQL: opérateur de déréférencement de tableau, intervalle
? t[0:1]; = list("a", "b")
L'opérateur de déréférencement de tableau
[?]
retourne une liste composée de tous les éléments de la collectionExample 31. OQL: opérateur de déréférencement de tableau, wildcard
? t[?]; = list("a", "b", "c")
67. Schéma exemple
Example 32. OQL: le schéma ODL utilisé dans la suite des exemples OQL
class Adresse { attribute int numero; attribute string voie; attribute int codepostal; attribute string ville; }; class Personne { attribute string prenom; attribute string nom; attribute Adresse adresse; }; class Etudiant extends Personne { attribute short annee; relationship set<Cours *> cours inverse Cours::etudiants; }; class Cours { attribute string titre; attribute string description; relationship set<Etudiant *> etudiants inverse Etudiant::cours; relationship Professeur *professeur inverse Professeur::cours; }; class Professeur extends Personne { relationship set<Cours *> cours inverse Cours::professeur; };
68. Création d'objets
Un objet est créé avec l'opérateur
new
, dont la syntaxe est la suivante:new classe( path:expression,...)
Les
path
sont des expressions construites avec l'opérateur.
à partir des attributs de la classeL'opérateur
new
retourne un OIDExample 33. OQL: création d'objet
? f := new Professeur( prenom:"Francois", nom:"Dechelle", adresse.numero:6, adresse.ville:"Paris"); = 2603.13.749757:oid ? \print Professeur {2603.13.749757:oid} = { Personne::prenom = "Francois"; Personne::nom = "Dechelle"; Personne::adresse Adresse = { numero = 6; voie = NULL; codepostal = NULL; ville = "Paris"; }; cours set<Cours*> = set { name = ""; count = 0; }; };
69. Collections
Une collection non ordonnée (set, bag) peut être modifiée à l'aide des opérateurs:
add
expr tocollection
suppress
expr fromcollection
Example 34. OQL: manipulation de collections non ordonnées
? c1 := new Cours( titre:"OOL", description:"Langages Orientes Objets"); = 2605.13.472965:oid ? c2 := new Cours( titre:"ODB", description:"Bases de Donnees Orientes Objets"); = 2608.13.487616:oid ? c3 := new Cours( titre:"RDB", description:"Bases de Donnees Relationnelles"); = 2611.13.754242:oid ? add c1 to f.cours; = 2605.13.472965:oid ? add c2 to f.cours; = 2608.13.487616:oid ? add c3 to f.cours; = 2611.13.754242:oid ? f.cours[?]; = list(2605.13.472965:oid, 2608.13.487616:oid, 2611.13.754242:oid) ? \print Cours {2605.13.472965:oid} = { titre = "OOL"; description = "Langages Orientes Objets"; etudiants set<Etudiant*> = set { name = ""; count = 0; }; *professeur = {2603.13.749757:oid}; }; Cours {2608.13.487616:oid} = { titre = "ODB"; description = "Bases de Donnees Orientes Objets"; etudiants set<Etudiant*> = set { name = ""; count = 0; }; *professeur = {2603.13.749757:oid}; }; Cours {2611.13.754242:oid} = { titre = "RDB"; description = "Bases de Donnees Relationnelles"; etudiants set<Etudiant*> = set { name = ""; count = 0; }; *professeur = {2603.13.749757:oid}; }; ? suppress c3 from f.cours; = 2611.13.754242:oid ? f.cours[?]; = list(2605.13.472965:oid, 2608.13.487616:oid) ? \print Cours {2605.13.472965:oid} = { titre = "OOL"; description = "Langages Orientes Objets"; etudiants set<Etudiant*> = set { name = ""; count = 0; }; *professeur = {2603.13.749757:oid}; }; Cours {2608.13.487616:oid} = { titre = "ODB"; description = "Bases de Donnees Orientes Objets"; etudiants set<Etudiant*> = set { name = ""; count = 0; }; *professeur = {2603.13.749757:oid}; };
70. Path expressions
L'opérateur
.
permet de naviguer dans les attributs d'un objet.Une expression écrite avec l'opérateur . est appelée path expression
Une path expression peut utiliser également l'opérateur de déréférencement de tableau sous ses différentes formes
Une path expression peut être utilisée en partie gauche d'une affectation
Une path expression peut être appliquée à une collection
Example 35. OQL: path expressions
? f.nom; = "Dechelle" ? f.adresse.numero; = 6 ? f.adresse.ville[0]; = 'P' ? f.adresse.ville[0] = 'p'; = false ? f.adresse.ville[0] := 'p'; = 'p' ? f.adresse.ville; = "paris" ? f.cours[?]; = list(2605.13.472965:oid, 2608.13.487616:oid) ? f.cours[?].titre; = list("OOL", "ODB")
71. Destruction d'objets
Un objet peut être détruit grâce à l'opérateur
delete
Example 36. OQL: destruction d'objets
? e1 := new Etudiant( prenom:"Albert", nom:"Dupont"); = 2659.13.815633:oid ? e2 := new Etudiant( prenom:"Roger", nom:"Leblanc"); = 2661.13.926087:oid ? e3 := new Etudiant( prenom:"Gerard", nom:"Martin"); = 2663.13.108819:oid ? add e1 to c1.etudiants; = 2659.13.815633:oid ? add e2 to c1.etudiants; = 2661.13.926087:oid ? add e1 to c2.etudiants; = 2659.13.815633:oid ? add e2 to c2.etudiants; = 2661.13.926087:oid ? add e3 to c2.etudiants; = 2663.13.108819:oid ? c1.etudiants[?].nom; = list("Dupont", "Leblanc") ? c2.etudiants[?].nom; = list("Dupont", "Leblanc", "Martin") ? \commit ? delete e3; = 2663.13.108819:oid ? c2.etudiants[?].nom; = list("Dupont", "Leblanc")
72. Requêtes
La syntaxe générale d'une requête est la suivante:
select [distinct] projection [from fromList [where predicat] [order by orderExprList [asc|desc]]
où:
distinct
indique que les duplications doivent être supprimées- projection est une expression utilisant les variables définies dans
fromList
- fromList est une séquence séparée par des virgules d'expressions de la forme:
- var in expr
- expr as var
- expr var
- predicat est une expression booléenne définie à l'aide des variables de fromList
- orderExprList est une séquence séparée par des virgules d'expressions pouvant être ordonnées
73. Requêtes : exemples
Example 37. OQL: requêtes
? select c from Cours c; = bag(2646.13.467986:oid, 2649.13.997619:oid, 2652.13.900257:oid) ? \print Cours {2646.13.467986:oid} = { titre = "OOL"; description = "Langages Orientes Objets"; etudiants set<Etudiant*> = set { name = ""; count = 2; }; *professeur = {2644.13.1037846:oid}; }; Cours {2649.13.997619:oid} = { titre = "ODB"; description = "Bases de Donnees Orientes Objets"; etudiants set<Etudiant*> = set { name = ""; count = 3; }; *professeur = {2644.13.1037846:oid}; }; Cours {2652.13.900257:oid} = { titre = "RDB"; description = "Bases de Donnees Relationnelles"; etudiants set<Etudiant*> = set { name = ""; count = 0; }; *professeur = {NULL}; }; ? select c.titre from Cours c; = bag("OOL", "ODB", "RDB") ? select struct(nom: p.nom, ville:p.adresse.ville) from Professeur p; = bag(struct(nom: "Dechelle", ville: "Paris")) ? select e.prenom from Etudiant e where e.prenom ~ "^A"; = bag("Albert") ? select p from Professeur p where p.prenom = "Francois"; = bag(2644.13.1037846:oid) ? \print Professeur {2644.13.1037846:oid} = { Personne::prenom = "Francois"; Personne::nom = "Dechelle"; Personne::adresse Adresse = { numero = 6; voie = NULL; codepostal = NULL; ville = "Paris"; }; cours set<Cours*> = set { name = ""; count = 2; }; }; ? select p.cours[?].titre from Professeur p where p.nom = "Dechelle"; = bag(list("OOL", "ODB")) ? select e.cours[?].titre from Etudiant e where e.prenom = "Albert"; = bag(list("OOL", "ODB")) ? select c.titre from Cours c where c.etudiants[?].prenom = "Albert"; = bag("OOL", "ODB")
74. EyeDB: les interfaces de programmation Java et C++
75. Principes
EyeDB fournit deux types d'interfaces de programmation:
- une bibliothèque client (C++, Java) supportant protocole client/serveur, connexion, accès au schéma...
- un mécanisme de traduction du schéma ODL vers des langages objets (C++, Java, Python, PHP5, Ruby...) permettant d'accéder aux fonctionnalités de persistance
Contrairement à l'approche Hibernate, les classes persistantes ne sont pas fournies par le code applicatif, mais générées
La génération est effectuée par l'outil
eyedbodl
. Le code généré utilise la bibliothèque client associée76. Interface Java
La compilation d'une application Java utilisant EyeDB comme support de persistance s'effectue en trois étapes:
- génération du code Java à partir du schéma ODL
- compilation du code Java généré, en utilisant l'archive
eyedb.jar
et génération d'une archive - compilation du code applicatif, en utilisant l'archive
eyedb.jar
et l'archive générée lors de la seconde étape
Le code applicatif utilisera la bibliothèque client pour l'initialisation de la connexion, l'exécution de requêtes OQL...
77. Exemple de code Java
Example 38. OQL: l'interpréteur
class Test { public static void main( String[] args) { try { // Initialisation du package 'eyedb' org.eyedb.Root.init("Test", args); // Initialisation du package 'linuxplus' linuxplus.Database.init(); // Ouverture de la base "linuxplus" linuxplus.Database db = new linuxplus.Database("linuxplus"); org.eyedb.Connection conn = new org.eyedb.Connection(); db.open(conn, org.eyedb.Database.DBRW); // Ouverture d'une transaction db.transactionBegin(); // Creation d'objets Course oodbms = new Course( db); oodbms.setTitle( "OODBMS"); oodbms.setDescription( "Object database management systems"); Student john_harris = new Student( db); john_harris.setFirstname( "John"); john_harris.setLastname( "Harris"); john_harris.setBeginYear( (short)2002); Teacher eric_viara = new Teacher( db); eric_viara.setFirstname( "Eric"); eric_viara.setLastname( "Viara"); oodbms.setTeacher( eric_viara); john_harris.addToCoursesColl(oodbms); // Ecriture des objets dans la base oodbms.store(org.eyedb.RecMode.FullRecurs); eric_viara.store(org.eyedb.RecMode.FullRecurs); john_harris.store(org.eyedb.RecMode.FullRecurs); // Affichage d'un objet oodbms.trace(); // Fin de la transaction db.transactionCommit(); } catch(org.eyedb.Exception e) { e.printStackTrace(); } } }
78. Hibernate, un framework de mapping objet-relationnel
79. Hibernate, introduction
Hibernate est un framework Java de mapping objet-relationnel, permettant de rendre persistant des objets Java dans une base de données relationnelle.
Le principe du mapping objet-relationnel repose sur:
- association entre classes Java et tables entité
- association entre relations entre objets (références, collections) et tables relation
Les objets Java rendus persistants sont des POJO (Plain Old Java Object) qui ne dépendent pas des classes Hibernate
Hibernate utilise l'API Java JDBC et supporte plusieurs SGBD relationnels (Oracle, DB2, SQL Server, MySQL, PostgreSQL...)
Hibernate fournit un langage de requête: HQL
80. Mise en oeuvre de Hibernate
Le développement d'une application utilisant Hibernate comprend les étapes suivantes:
- implémentation du code Java des POJO
- description du mapping dans les fichiers de mapping
- implémentation du code applicatif utilisant les POJO et l'API Hibernate
Les archives JAR suivantes doivent être incluses dans le CLASSPATH:
- le JAR contenant les classes Hibernate:
hibernate3.jar
- les JAR des bibliothèques Java utilisées par Hibernate
- le JAR du driver JDBC choisi
81. Configuration
Le fichier de configuration de Hibernate permet de spécifier à l'aide de propriétés des éléments tels que URL JDBC, informations de connexion au SGBD
Le fichier de configuration permet de plus de spécifier les fichiers de mapping à charger
Example 39. Hibernate: fichier de configuration
<hibernate-configuration> <session-factory> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost/quicktour</property> <property name="connection.username">quicktour</property> <property name="connection.password">quicktour</property> ... <mapping resource="Personne.hbm.xml"/> <mapping resource="Cours.hbm.xml"/> <mapping resource="Etudiant.hbm.xml"/> <mapping resource="Professeur.hbm.xml"/> </session-factory> </hibernate-configuration>
82. Les propriétés de configuration
Nom Description hibernate.connection.driver_class
classe du driver JDBC hibernate.connection.url
URL JDBC hibernate.connection.username
utilisateur de la base de données hibernate.connection.password
mot de passe de la base de données hibernate.dialect
le nom de la classe du dialect Hibernate, pour l'utilisation de certaines fonctionnalités spécifiques à la plateforme, par exemple: net.sf.hibernate.dialect.PostgreSQLDialect
,net.sf.hibernate.dialect.MySQLDialect
,net.sf.hibernate.dialect.OracleDialect
,net.sf.hibernate.dialect.SQLServerDialect
...hibernate.show_sql
affichage des requêtes SQL générées hbm2ddl.auto
vide la base et recrée le schéma au démarrage 83. Implémentation d'une classe persistante
Une classe destinée à être persistente est une classe Java standard:
- POJO (Plain Old Java Object)
- attributs associés à des méthodes
get
/set
- redéfinition conseillée des méthodes
equals
ethashCode
Example 40. Hibernate: classe persistente
class Personne { public Personne() {} public void setNom( String nom) {...} public String getNom() {...} public boolean equals( Object other) {...} public int hashCode() {...} private Long id; private String prenom; private String nom;
84. Fichier de mapping
Un fichier de mapping est un document XML utilisé pour spécifier, pour chaque classe à rendre persistente
- la table utilisée
- l'identifiant unique (clé primaire> avec l'élément
<id>
- l'association entre attributs de la classe et colonnes de la table
- l'implémentation des relations...
Example 41. Hibernate: fichier de mapping simple
<hibernate-mapping> <class name="Personne" table="PERSONNE"> <id name="id" column="PERSONNE_ID"> <generator class="native"/> </id> <property name="prenom"/> <property name="nom"/> </class> </hibernate-mapping>
85. Les classes Session et SessionFactory
La classe
Session
permet d'accéder aux fonctionnalités de Hibernate: chargement/sauvegarde d'objets, transactions, requêtes.Une instance de la classe
Session
est obtenue à partir de laSessionFactory
qui initialize Hibernate et charge la configurationExample 42. Hibernate: ouverture d'une session
class Exemple { private static final SessionFactory sessionFactory; static { try { sessionFactory = new Configuration().configure().buildSessionFactory(); } catch (HibernateException ex) { throw new RuntimeException("Erreur configuration:"+ex.getMessage(), ex); } } Session openSession() { if (session == null) session = sessionFactory.openSession(); return session; } void closeSession() { if (session != null) session.close(); session = null; } private Session session; }
86. Transactions
Tous les accès aux objets persistants doivent se faire à l'intérieur d'une transaction, obtenue à partir de la session Hibernate à l'aide de la méthode
beginTransaction
Une fois les opérations sur les objets persistants effectuées, la transaction peut être:
- validée par l'appel de la méthode
commit()
- abandonnée par l'appel de la méthode
rollback()
Example 43. Hibernate: transaction
class Exemple { void ex1() { Session session = openSession(); Transaction tx = session.beginTransaction(); ... tx.commit(); closeSession(); } }
87. Création d'objets persistants
Un objet persistant est créé comme un objet Java standard, à l'aide de l'opérateur
new
L'objet devient persistant quand il est sauvegardé par l'appel de la méthode
save(Objet obj)
de la classeSession
Example 44. Hibernate: création d'objet persistant
class Exemple { void ex2() { Session session = openSession(); Transaction tx = session.beginTransaction(); Personne p = new Personne(); p.setPrenom( "Albert"); p.setNom( "Lebrun"); session.save( p); tx.commit(); closeSession(); } }
88. Chargement d'objets
Une première manière de charger un objet depuis la base de données est d'utiliser la méthode
load
de la classeSession
, à condition de connaître l'identifiant (id
) de l'objet à chargerExample 45. Hibernate: chargement d'objet persistant
class Exemple { void ex3( int id) { Session session = openSession(); Transaction tx = session.beginTransaction(); Personne p = (Personne)session.load( Personne.class, id); System.out.println( p); tx.commit(); closeSession(); } }
89. Mise à jour d'objets persistants
Un objet qui a été mis à jour (modification des attributs) est sauvegardé automatiquement à la fin de la session par l'appel de la méthode
flush
de la classeSession
; ceci est fait automatiquement si la méthodecommit
de la transaction est appeléeSi l'objet a été modifié après la fin de la session, il peut être sauvegardé dans une nouvelle session par l'appel de la méthode
update
de la classeSession
Example 46. Hibernate: mise à jour d'objet persistant
class Exemple { void ex4() { Session session1 = openSession(); Transaction tx = session1.beginTransaction(); Personne p = new Personne(); p.setPrenom( "Albert"); p.setNom( "Lenoir"); session1.save( p); tx.commit(); closeSession(); p.setPrenom( "Gustave"); // modification hors transaction Session session2 = openSession(); Transaction tx = session2.beginTransaction(); session2.update( p); tx.commit(); closeSession(); } }
90. Destruction d'objets
Un objet persistant peut être détruit par l'appel de la méthode
delete(Objet obj)
de la classeSession
. Cet appel supprimera l'objet de la base de données, mais l'objet Java restera accessibleExample 47. Hibernate: destruction d'objet persistant
class Exemple { void ex5( int id) { Session session = openSession(); Transaction tx = session.beginTransaction(); Personne p = (Personne)session.load( Personne.class, id); session.delete( p); tx.commit(); closeSession(); } }
91. Collections
Un objet persistant peut contenir des attributs de type
Collection
Hibernate impose que les attributs soient typés par des interfaces et non des classes concrètes
Un attribut de type collection est associé à un élément collection dans le fichier de mapping, l'élément dépendant du type Java de la collection (par exemple élément
<set>
pour une collection de typeSet
)Example 48. Hibernate: collections
<hibernate-mapping> <class name="Professeur" table="PROFESSEUR"> <set name="cours"> ... </set> </class> </hibernate-mapping> class Professeur extends Personne { Professeur() { cours = new HashSet(); } private Set cours; }
92. Gestion des relations
Les attributs de type collection servent la plupart du temps à gérer des relations entre instances de classes différentes.
Hibernate fournit un support pour les relations one-to-one, one-to-many, many-to-many avec gestion de l'intégrité référentielle
L'implémentation de la relation peut utiliser ou non une table supplémentaire, suivant la cardinalité de la relation (une relation many-to-many utilise nécessairement une table de relation)
Les relations sont déclarées dans le fichier de mapping, en précisant la cardinalité, les classes en relation...
93. Relations : exemple one-to-many
Example 49. Hibernate: relation one-to-many
<hibernate-mapping> <class name="Professeur" table="PROFESSEUR"> <set name="cours" inverse="true"> <key column="PERSONNE_ID"/> <one-to-many class="Cours"/> </set> </class> </hibernate-mapping> <hibernate-mapping> <class name="Cours" table="COURS"> <many-to-one name="professeur" column="PERSONNE_ID"/> </class> </hibernate-mapping> class Professeur extends Personne { ... private Set cours; } class Cours { private Professeur professeur; }
94. Relations : exemple many-to-many
Example 50. Hibernate: relation many-to-many
<hibernate-mapping> <class name="Cours" table="COURS"> <set name="etudiants" table="ETUDIANT_COURS" inverse="true"> <key column="COURS_ID"/> <many-to-many column="ETUDIANT_ID" class="Etudiant"/> </set> </class> </hibernate-mapping> <hibernate-mapping> <class name="Etudiant" table="ETUDIANT"> <set name="cours" table="ETUDIANT_COURS" inverse="true"> <key column="PERSONNE_ID"/> <many-to-many column="COURS_ID" class="Cours"/> </set> </class> </hibernate-mapping> class Etudiant extends Personne { private Set cours; } class Cours { private Set etudiants; }
95. Héritage
Hibernate supporte l'héritage de classes Java, chaque classe pouvant avoir son propre fichier de mapping.
Hibernate propose plusieurs stratégies de mapping pour les classes dérivées:
- une table par hiérarchie de classes
- une table par sous-classe
Dans le cas d'une table commune, une colonne discriminator servira à typer les enregistrements contenus dans la table en fonction de la sous-classe
96. Héritage: exemples
Example 51. Hibernate: héritage, table commune
<hibernate-mapping> <class name="Personne" table="PERSONNE"> <discriminator column="TYPE_PERSONNE" type="string"/> <subclass name="Professeur" discriminator-value="PROFESSEUR"> ... </subclass> <subclass name="Etudiant" discriminator-value="ETUDIANT"> ... </subclass> </class> </hibernate-mapping> class Professeur extends Personne { ... } class Etudiant extends Personne { ... }
Example 52. Hibernate: héritage, tables séparées
<hibernate-mapping> <joined-subclass name="Professeur" table="PROFESSEUR" extends="Personne"> <key column="PERSONNE_ID"/> ... </joined-subclass> </hibernate-mapping> class Professeur extends Personne { ... }
97. Langage de requêtes HQL
Le langage de requêtes HQL permet d'exprimer des requêtes au niveau objet, en employant attributs des classes, prédicats de sélection...
Une requête HQL a la forme suivante:
select selectExpr from fromList where whereList
:selectExpr
utilise les variables définies dans lafromList
fromList
définit des variables à l'aide de déclarations du typeexpr [as] var
98. HQL: exemples
Example 53. Hibernate: exemple de requêtes HQL
from Professeur from Professeur as prof from Professeur as prof where prof.prenom = "francois" from Etudiant as e where e.nom like "Mar*" select e.nom from Etudiant as e where e.prenom like "Al*" select new Personne( e.prenom, e.nom) from Etudiant as e
99. HQL: exécution d'une requête
Une requête est exécutée par l'intermédiaire de la
Session
- la méthode
createQuery( String s)
retourne une instance de la classeQuery
- les méthodes
setXXX( XXX x)
de la classeQuery
permettent de donner des valeurs aux paramètres de la requête - la méthode
list()
exécute la requête et retourne les résultats sous forme de collection
Example 54. Hibernate: exécution d'une requête HQL
class Exemple { void ex6( String nom) { Session session = openSession(); Transaction tx = session.beginTransaction(); String s = "from Professeur as prof where prof.nom like ?"; Query q = session.createQuery( s); q.setString( 0, nom); List resultats = q.list(); // ... parcours a l'aide d'un Iterator tx.commit(); closeSession(); } }
100. Travaux dirigés
101. EyeDB : compilation et installation
Les sources de EyeDB peuvent être téléchargées depuis: http://sf.net/projects/eyedb
La compilation se résume à:
tar xvzf eyedb-2.8.7.tar.gz cd eyedb-2.8.7 ./configure --prefix=$HOME/eyedb make make install
Compiler EyeDB et l'installer, puis exécuter le script d'initialisation eyedb-post-install.sh
Vérifier que l'installation fonctionne en lançant le serveur EyeDB avec les commandes eyedbctl start puis eyedbctl status
102. EyeDB : administration basique
Utiliser eyedbadmin pour créer:
- une base de données
- un utilisateur (non Unix)
- donner les droits d'accès administration à l'utisateur créé pour la base créée
103. L'application exemple
On veut réaliser un logiciel de gestion intégrée de documents (livres, journaux, CD, DVD, MP3...) qui permettra par exemple la recherche dans l'ensemble des documents.
Modéliser de la façon la plus simple possible les différents types de documents présents:
- un livre contient un (des) auteur(s), un titre, un éditeur
- un CD contient un titre, un (des) auteurs, une liste de pistes
Un auteur est identifié par un nom.
A chaque document peut être associé une liste de mots clés
Le système doit permettre deux types de recherche:
- chercher tous les documents dont le titre ou l'auteur contient une chaîne de caractères donnée
- chercher tous les documents associés à un mot clé donné
104. EyeDB : définition d'un schéma ODL
Définir un schéma ODL pour l'application exemple donnée précédemment. Ce schéma définira les classes:
Document
CD
Livre
Auteur
Implémenter les relations avec intégrité référentielle en utilisant les collections
set
et les attributs inverses.105. EyeDB : utilisation du langage OQL
Réaliser un script OQL qui insère dans la base des objets des classes définies (
Auteur
,Livre
,CD
).Vérifier que les objets insérés respectent les contraintes d'intégrité référentielle précédemment définies.
Détruire un des objets créés et vérifier que les contraintes d'intégrité référentielle sont toujours valides.
Réaliser un script OQL de requêtes implémentant les recherches définies dans l'application exemple:
- chercher tous les documents dont le titre ou l'auteur contient une chaîne de caractères donnée
- chercher tous les documents associés à un mot clé donné
Dans un but de simplicité, la recherche ne portera que sur les attributs définis dans la classe de base
Document
(la recherche générique dans les classes dérivées nécessite l'écriture d'une méthode OQL).106. EyeDB : utilisation du binding Java
Ecrire une application Java qui utilise le binding Java pour réaliser les fonctions précédemment implémentés en OQL:
- insertion d'objets dans la base
- recherche par chaîne de caractères
L'implémentation d'une application Java se fait en 3 temps:
- génération du code Java pour les classes
Auteur
,Document
,Livre
,CD
à partir du schéma ODL déjà écrit - compilation du code Java généré en utilisant l'archive
eyedb.jar
- écriture de l'application et compilation en utilisant le code généré et l'archive
eyedb.jar
107. Hibernate
Implémenter avec Hibernate l'application exemple déjà réalisée avec EyeDB
Le développement de l'application comprend les étapes suivantes:
- écriture des classes POJO
Auteur
,Document
,Livre
,CD
- écriture des fichiers de mapping Hibernate pour ces classes et du fichier de configuration de Hibernate
- écriture de l'application Java qui créée des objets, les sauvegarde, lance des requêtes HQL...
Les archives Java fournies dans les répertoires
distrib/hibernate
,distrib/jdbc
,distrib/slf4j
sont à utiliser de la façon suivante:- pour la compilation du code Java, seule l'archive
hibernate3.jar
est nécessaire - pour l'exécution de ce même code, toutes les archives fournies dans ces répertoires doivent être ajoutées au
CLASSPATH
Le SGBDR utilisé est MySQL; la création de la base n'est pas réalisée par Hibernate et doit être faite avant le lancement de l'application. Un script de création de base MySQL est donné dans le répertoire
code/cours/hibernate/scripts
Cours ESIEADroit d'auteur
Auteur : François Déchelle
Version 1.3
Ce document est distribué sous les termes du contrat Creative Commons Paternité-Partage à l'identique-Pas d'utilisation commerciale
Source : http://www.dechelle.net/pub/esiea/odb/html/1/index.html