Persistence.

Besoin

Enregistrer un état de manière permanente.

Il n'y aurait pas besoin de persistance si la mémoire de travail des ordinateurs :

  • n'était pas volatile (nécessitant une alimentation en courant pour être maintenue)
  • avait un coût moindre (permettant de l'augmenter à la taille des disques durs typiquement).

Analyse

Sauvegarder l'état d'un objet consiste à enregistrer la valeur de l'ensemble de ses champs (attributs), qu'ils soient :

  • simples (numérique, texte, booléen, etc.)
  • objet (référence à un autre objet, collection d'objets, etc.)

Cas d'utilisation

Il existe plusieurs cas où l'on a besoin d'un mécanisme de persistance. Tous impliquent un modèle objet et un modèle de stockage :

  • top-down : le modèle objet existe (ou est imposé), et l'on souhaite générer modèle de stockage. Cela aboutit typiquement à une génération de schéma de base relationnelle à partir d'un ensemble de classes Java.
  • bottom-up : le modèle de stockage existe (ou est imposé), et l'on souhaite générer le modèle objet. Cela aboutit typiquement à une génération de classes Java à partir d'un schéma relationnel.
  • meet-in-the-middle : le modèle de stockage et le modèle objet existent (ou sont imposés), et l'on souhaite faire correspondre l'un avec l'autre.

Dans tous les cas, une formalisation de la correspondance (mapping) entre les 2 modèles devra être produite.

Conception

Alors que la persistance d'objets est relativement naturelle dans un SGBD utilisant le même paradigme (SGBDO), elle vise la plupart du temps un stockage dans selon un paradigme relationnel (SGBDR). Dans ce dernier cas doit être mis en place une correspondance (mapping) entre le modèle objet et le modèle de la base relationnelle (Object/Relational ou O/R).

Héritage

On peut représenter un héritage objet via un mapping relationnel :

Mappings d'héritage
Vertical Horizontal Filtré ou "plat" (flat)
Contraintes schéma Nombre de tables par hiérarchie 3ème forme normale : 1 par classe (concrète ou abstraite) 1 par classe concrète 1 pour l'ensemble des classes
Mécanisme de typage Fonction de la table pour les classes concrètes. Stocké dans une colonne discriminante ou dans une table annexe pour les classes abstraites Fonction de la table Stocké dans par une colonne discriminante
Evolutivité Modification de classes ancètres Modification de la table de la classe ancêtre Modification de toutes les tables Modification de la table unique
Modification/ajout de classes dérivées Modification/ajout de tables Modification/ajout de tables Modification de la table unique
Performance Lecture sans relation Mauvais Moyen Bon
Lecture avec relation Bon Mauvais Moyen
Contraintes Espace alloué Minimal Moyen Grand
Intégrité Très adapté Moyennement adapté Pas adapté

Relations

On peut représenter des relations via un mapping relationnel :

Simple Entité Inversée
Contraintes schéma Principe La table source contient une clé étrangère vers la destination 1 Table intermédiaire contient les clés des objets liés La table destination contient une clé étrangère vers la source
Performance/ type de relation 1-1 Bon Mauvais Moyen
1-n Impossible Moyen Bon
n-m Impossible Bon Impossible

Cependant le mapping peut se révéler plus complexe lorsqu'il faut garantir des contraintes :

  • d'intégrité (1-1, 1-n)
  • d'ordre (relation avec collections ordonnées)

Exemples

Des exemples de solutions de persistance sont :

Solution SQL Alchemy ORM CocoBase Castor-JDO Entités EJB Hibernate JDBC JDO ObjectSpaces ODMG SDO Serialisation TopLink Torque Versant Commentaire
Version 1.3.0b1 4.5 0.9 1 2 3 2 1 2 9.0.3 3.1
Transactions Explicites session.commit() JTA

JTA

JTA Oui javax.jdo. Transaction ou JTA Oui Transaction tx = odmg.newTransaction() Non Oui tx.begin, tx.commit
Implicites ? Si encapsulsé dans EJB Non transaction-attribute (Descripteur) Si encapsulsé dans EJB Non Oui si en environnement géré (JCA) et encapsulé dans EJB DataSet ? Non Non Si encapsulsé dans EJB Si encapsulsé dans EJB Si intégré dans un serveur applicatif et encapsulsé dans EJB Démarcation, propagation spécifiées en dehors du code.
Pessimistes ? Exclusive Oui Oui Oui Oui Oui Oui Non Oui Verrous
Optimistes ? Oui Shared Non Oui Non Oui Oui Non Oui Oui Sans verrous
Distribuées sessionmaker(twophase=True) JTS JTS JTS JTA+JTS JTS JTS Non Non Non Support de XA
Mémoire ? Non Non Oui Non Non Non Commit ou rollback d'opérations en mémoire
Cycle de vie Callbacks ? EntityBean API InstanceCallbacks InstanceCallbacks extends LoadCallback, StoreCallback,
ClearCallback, DeleteCallback
Non readObject, writeObject... Avant/après lecture, mise à jour, suppression
Requêtes Langage objet ? EJB-QL, API CBQuery Builder Castor OQL SQL EJBQL HQL SQL JDOQL OPath OQL Non imposé Non TopLink Expression, EJB QL, PL/SQL API Criteria OQL
Projections, vues ? Non Oui Non query.setResult(this ou champ ou variable, expression navigationnelle, paramètre) Oui Non
Fonctions aggrégats ? Non Oui Non query.setResult(count ou sum ou min ou max ou avg ou expression numérique) Oui Non
SQL possible ? Database:: getOQLQuery ("CALL SQL ...") Dépend des implémentations Oui Oui Dépend des implémentations

q = pm.newQuery ("javax.jdo.query.SQL", "SELECT ...")

Non
Accès au code ? Non Non Non Non Non Non Oui Non Non Oui Invocation de méthodes dans des requêtes typiquement
Performance Cache ? Oui Oui Oui Oui Non Oui Oui Non Oui Managers Oui
Détection des modifications ? Non Oui Proxy Non Enhancement Oui Non Via les accesseurs (mutators)
Transparence Accès aux informations ? Réflexivité Java Réflexivité Java Réflexivité Java Réflexivité Java API Enhancement API Réflexivité Java Réflexivité Java Code généré Enhancement
Relations (1-n, n-m) ? Oui Oui Non via accesseurs Oui Oui N/A Oui Oui Oui Oui Oui Oui
Héritage polymorphic_identity, polymorphic_on __mapper_args__ Oui Oui Non Oui Oui N/A Oui (méthode(s) dépendant de l'implémentation) <inheritance strategy="new-table" ou "superclass-table" ou "no-table"> Oui Oui Oui Plat Oui
Collections relationship(Class, lazy="dynamic"), filter() Collection, Set Non Oui DBag, DSet, DList, DArray, DMap Oui Oui
Persistance de proche en proche ? Non N/A Oui Oui Oui Persistence by reachability
Non intrusion dans le code des objets métier ? Méthodes d'accès aux données obligatoires Implémentation de SessionBean, EntityBean, MessageDrivenBean Oui Méthodes d'accès aux données obligatoires API JDBC Oui Classe abstraite comportant des méthodes OnCreate, etc. Non Implémentation de Serializable Méthodes d'accès aux données obligatoires Héritage de code généré Oui Pour maintenabilité et réutilisabilité des objets métier.
Accès au graphe d'objets dépendants ? Non Oui Non Oui Non Oui Non Oui
Accès au modèle métier ? Oui Oui Oui Non Oui Oui Oui Non Oui
Mapping Multi-tables ? Oui Dépend de l'implémentation Non Dépend de l'implémentation <join table="DELIV" column="ADDR_STREET"/> Flux (fichier) Oui Base objet
Top-down ? Oui Dépend de l'implémentation Non Dépend de l'implémentation Ecriture de fichier Oui Génération du schéma de la base à partir du modèle objet
Bottom-up ? Oui Dépend de l'implémentation Non Dépend de l'implémentation Non Génération du modèle objet à partir du schéma d'une base existante
Granularité fine ? Objet Via SQL Champ Objet Oui
Stockage Paradigme libre ? SGBDR, XML, LDAP Non spécifié (mais généralement SGBDR) SGBDR SGBDR Oui (via JCA) SGBDR, XML SGBDO, SGBDR Flux (fichier) SGBDR SGBDR

Versant

Support d'une base existante ? Oui Oui Oui Manuel Oui Identité imposée Flux (fichier) Oui Oui Versant
Portabilité API standard ? Produit org.exolab.castor javax.ejb cirrus.hibernate java.sql, javax.sql javax.jdo Microsoft. ObjectSpaces org.odmg java.io Produit Apache DB com.versant Un standard offre un plus large choix d'implémentations (moins de risque de vendor-locking) et une meilleure perennité
J2ME Python Non Windows .Net
J2SE Python 1.2 Non Oui 1.2 1.1 1.2 1.3 Windows .Net 1.1 1.1 1.2
J2EE Python WAS, WLS, OAS, BES... 1.2 1.3 1.5 1.2 1.3 (JCA) Windows .Net 1.2 WAS, WLS, OAS WAS, WLS...
Implémentations BEA, IBM, Oracle... Sun, IBM... Xcalia, SolarMetrics, Hemisphere... Poet... Sun, IBM... Apache
Utilisabilité modèle statique ? EJB POJO Non POJO
modèle dynamique ? Non Texte SQL, noms de colonnes, etc. Non
Métadonnées __tablename__, Column(type), introspection via inspect() Fichier XML API Introspection Java, métadonnées de persistance XML Interrogeables
Licence MIT Thought, Inc. Style BSD J2EE LGPL J2SE Variable MicroSoft IBM, BEA J2SE Apache Versant

Limitations

La persistance de certaines informations devient problématique lorsque ces informations ne sont :

  • pas directement accessibles par le moteur de persistance (informations mémoires depuis Java par exemple)
  • pas rétablissables par nature (propres à une localisation géographique typiquement)

Voir