Le logo de JDOJava Data Objects : objets de données Java.

Besoin

Gérer la persistance d'objets Java de manière :

Analyse

JDO vise à ajouter à des POJO une capacité de persistance de manière "orthogonale", c'est-à-dire sans contraintes pour ces objets (suivant en cela l'approche AOP, en ajoutant un aspect "persistance" aux objets).

En particulier il vise à garantir une indépendance :

  • du support de stockage (datastore), qui peut être un SGBDR, un SGBDO, des fichiers XML, un mainframe, etc.
  • du fournisseur de l'implémentation JDO, car l'API et l'enrichissement (enhancement) de code sont garanties portables dans d'autres implémentations JDO.
  • de la plate-forme d'exécution, également portable sur :
    • diverses plates-formes natives (OS et machine), grâce et Java
    • au sein de Java-même, dans des contextes :
      • non gérés : applications autonomes (standalone)
      • gérés (managed) : applications déployées dans un serveur J2EE.

JDO accède au support de stockage (datastore) via le moyen de son choix. Il peut s'agir de pilotes JDBC ou de connecteurs JCA dans le cas d'applications J2EE.

Cas d'utilisation

JDO APIOn peut distinguer 3 types de classes dans une application utilisant JDO :

  • non-enhancées, n'ayant aucun lien avec JDO
  • persistence capable (PC) : les classes d'objets capables de persister leurs données et/ou de les modifier transactionnellement. Comme indiqué précédemment ces classes n'ont rien de particulier, hormis le fait que leur code a été enrichi après leur compilation.
  • persistence aware : les classes conscientes de la persistance des persistance capable, utilisant l'API JDO pour les manipuler (requêtes de recherches multi-critères, délimitation des transactions, changement d'état JDO, etc.). Ces classes n'ont en fait rien rien de particulier, et persistence aware se réduit plus à un rôle sans conséquence technique. La seule exception est le cas rare (et peu recommandé) où elles souhaiteraint accéder directement (sans passer par des méthodes) aux champs public/package/protected d'une classe persistence capable (elles devront alors être enhancées comme les persistence capable pour assurer la transparence de ces accès).

Persistence capable

Un objet JDO persistence-capable est un objet Java capable d'être :

  • transactionnel : Les modifications depuis le dernier début de transaction peuvent être annulées (l'état précédent est rétabli)
    • persistant de manière transparente (sans que le développeur ait à modifier son code source).
    • transitoire (transient) : en mémoire

Cette capacité lui est donnée après modification de son code (généralement son code compilé, ou bytecode) par outil. Cette instrumentation du code après compilation est appelée enhancement (enrichissement de code). Cet enhancement se base sur un descriptif des classes à rendre persistence-capable (définissant les classes et champs à rendre persistants, les champs caractérisant l'identité d'un objet, etc.), nommé métadonnées (metadata).

L'ensemble des états décrits ci-dessus (transactionnel-persistant, transactionnel-transitoire) est généralement qualifié d'ensembles des états "gérés" (managed), puisque c'est dans ces cas que la gestion JDO apporte une valeur ajoutée. Ceci dit un objet enhancé peut également passer en état transitoire-non transactionnel, c'est à dire ayant un comportement identique à des objets Java classiques ou JDO ne s'interpose plus.

Outre sa classe et les champs qui composent son état, un objet Persistence Capable est caractérisé par son identité qui peut être :

  • durable : quand l'objet est persistant
    • gérée par JDO (datastore identity), qui génère et récupère implicitement une identité pour chaque instance.
    • applicative (application identity) : le développeur spécifie alors dans ses métadonnées JDO une combinaison de champs de l'objet (qui seront typiquement associés à leurs colonnes équivalentes dans un SGBDR). Un cas particulier et courant de ce type d'identité est celui d'une identité composée d'un seul champ simple. On parle alors d'identité simple (simple identity).
  • non durable : pour les transactions en mémoire

Persistence aware

Les classes manipulant les objets persistence capable effectuent des :

  • lectures :
    • recherche par identifiant unique
    • recherche multi-critères (requête JDO QL), itération sur les résultats, tris, etc.
    • lecture partielles (groupe de champs chargés par défaut, et non pas tous les champs d'un objet)
    • lecture non transactionnelles : plus performantes mais pouvant être incohérentes (un attribut lu n'est pas garanti cohérent avec un autre lu précédement par exemple).
  • écritures : modification de l'état
    • automatiquement répercuté en base lors de la validation de la transaction
      • optimiste :la transaction est gérée par JDO, aucun verrou n'est maintenu, et la vérification de non-concurrent se fait en fin de transaction. Particulièrement adapté aux applications définissant des transactions dépendantes d'actions clients potentiellement longues ("think time" du client incompatible avec le maintient de verrous).
      • pessimistes : la transaction est gérée par le SGBD, qui maintient des verrous durant celle-ci afin de prévenir des écritures concurrentes.
    • répercuté uniquement dans le cache, en cas d'écriture non transactionnelle.

Conception

JDO SPIPersistence capable

Pour être géré (managed) par JDO, un objet doit implémenter un contrat de Persistence Capable via une instrumentation (enhancement) du bytecode de sa classe. Cette post-compilation ajoute au code des méthodes et champs additionnels, et du code statique permettant d'interragir avec l'infrastructure JDO (de tel ou tel fournisseur, l'enhancement étant standard et n'imposant donc pas de modification des classes métier si l'on change de fournisseur JDO).

Comme il s'agit de l'implémentation d'une interface, il est également possible - mais jamais fait en pratique - d'utiliser d'autres techniques que l'enhancement, telle que :

  • préprocesseur : la modification du code source avant compilation.
  • générateur : génération du code source des classes métier incluant directement leur enhancement JDO. Peu d'intérêt car l'utilisation d'un enhancer est plus pratique et sûre que d'écrire un générateur de source devant connaître le code d'enhancement de JDO.
  • manuel : rédaction du code source en implémentant explicitement l'interface PersistenceCapable, les méthodes du contrat JDO, etc. Ceci cette méthode n'a aucun intérêt puisque le code d'un PersistenceCapable est systématiquement le même, et l'écrire soi-même conformément à la spécification JDO laisse toujours la possibilité d'une erreur du rédacteur.

La correspondance (mapping) entre l'état mémoire de l'objet et son état persistant est rédigé dans un descripteur standard, externe au code (fichier XML), pouvant comporter des extensions propriétaires.

L'accès aux données peut être :

  • explicite, en fournissant à la fabrique de PersistenceManager un ensemble de propriétés (pilote JDBC, URL de connexion JDBC, login et password) similaires à celles requises par un DriverManager JDBC.
  • abstrait via une fabrique de connexions (connection factory), pouvant correspondre à une DataSource JDBC. Il s'agit alors d'un déploiement en "environnement géré" (J2EE), où l'implémentation JDO utilise JCA pour s'intégrer avec le serveur applicatif.

Implémentation

Etats JDO
Transactionnel Non transactionnel
Persistant Lectures
Transitoire Comportement identique à celui d'un objet non JDO
Optimisations Ecriture dans le cache NonTransactionalWrite=true
Lecture non synchronisée NonTransactionalRead=true
Recherche dans le cache ignoreCache=false

Type Description
Optimisations Conservation du cache après transaction retainValues=true
Non-restauration après annulation restoreValue=false
Ecriture dans le cache NonTransactionalWrite=true
Lecture non synchronisée NonTransactionalRead=true
Recherche dans le cache ignoreCache=false
Transactions JDO

Egalement le JDO Query Language (JDOQL) permet d'obtenir des instances ou collections d'instances JDO d'un type donné, éventuellement filtrées par divers critères exprimés dans une syntaxe proche de celle du langage Java.

Filtres JDOQL
Forme Commentaire
Egalité Avec contante champ == valeur, champ != valeur, champ == null, champ != null
Entre champs champ1 == champ2
Comparaison Caractères chaîne > valeur
chaîne < valeur
chaîne1 < chaîne2
chaîne1 > chaîne2
Pour les types non numérique, l'interprétation est dépendante de l'implémentation / du support de persistance
chaîne.startsWith (valeur), chaîne.endsWith (valeur)
Expression expression1 && expression2
expression1 || expression2
Collections Existence d'un élément caractérisé collection.contains (var) && expression (var)
Vide collection.isEmpty()

Des contraintes peuvent également être imposées sur les ensembles résultats retournés, qui peuvent être :

  • triés (ascendant, descendant) sur un ou plusieurs champs, par exemple pour des collections non ordonnées

API

L'API de JDO est définie dans le package javax.jdo.

On peut distinguer trois types de classes dans une application JDO :

  • les classes d'objets potentiellement persistant et/ou transactionnels. Ces classes n'ont rien de particulier, hormis le fait qu'elles implémenteront PersistenceCapable suite à leur post-compilation (enhancement). Tout ou partie de leur champs (selon le mapping spécifié) sera alors pris en charge par JDO à l'exécution. Leur identité peut être gérée par JDO de manière transparente (non durable ou datastore id) ou applicative et donc explicite (application id). Dans ce dernier cas une classe d'identité applicative doit exister, semblable à celle des EJB (combinaison publique, unique et sérialisable de champs de l'objet, avec constructeur par défaut, equals() et hashCode()).
  • les classes conscientes de la persistance (persistence aware), utilisant l'API JDO pour manipuler des objets PersistenceCapable. Ces classes utilisent typiquement des PersistenceManager, aptes à exécuter des requêtes, démarrer/terminer des transactions, ou changer l'état des objets JDO (persistant, transient, transactionnel, etc.). Les PersistenceManager sont obtenus via une PersistenceManagerFactory.

Une implémentation JDO doit au moins supporter une des identités SGBD.

SPI

En dehors de l'API visible par les développeurs utilisant JDO, comment cela fonctionne-t-il "à l'intérieur" ?

A l'exécution, toute instance JDO "enhancée" référence un gestionnaire de son état (StateManager) qui communique avec le PersistenceManager pour gérer la persistance.

Le StateManager, chargé de gérer le cycle de vie d'une (ou plusieurs) instances, considère plusieurs états possibles dans la vie du d'un PersistenceCapable :

  • transitoire (en mémoire)
    • non transactionnel (transient). C'est l'état de n'importe quel objet décrit dans les métadonnées JDO au démarrage de l'application.
    • (optionnel) transactionnel, après un pm.makeTransactional(pc)
      • non modifié dans la transaction (transient-clean)
      • modifié dans la transaction (transient-dirty), après un pc.setXxx(v).
  • persistant
    • (optionnel) non transactionnel (persistent-nontransactional)
    • transactionnel
      • nouvellement créé dans la transaction (persistent-new), après un pm.makePersistent(pc) ou sur un autre pc référençant ce pc par exemple (persistance de proche en proche).
        • nouvellement créé puis supprimé dans la transaction (persistent-new-deleted)
      • vide (hollow), l'état persistant n'ayant pas encore été chargé, après un pc=getObjectById() par exemple
      • modifié dans la transaction (persistent-dirty), après un pc.setXxx(v) par exemple
      • non modifié dans la transaction (persistent-clean)
      • supprimé dans la transaction (persistent-deleted), après un pm.deletePersistent(pc) par exemple.

FAQ

  • Est-ce que JDO peut être plus rapide que du code JDBC pur ? Oui, en fonction de l'utilisation du cache où du pooling de connexions propres à toute implémentation JDO, mais aussi grâce au code généré, optimisé pour exploiter l'ensembles des possibilités de JDBC (requêtes précompilées, pooling, curseurs) et des spécificités de tel ou tel SGBD.
  • J'ai effectué un comparatif et mon code JDBC se révèle plus rapide, pourquoi ? Cela peut être dû au fait que vous vous limiter à récuperer des colonnes de tables et non des objets complets. Un comparatif représentatif doit comparer la création/modification/lecture de données sous forme d'objets et sur un nombre conséquent de transactions.
  • Comment choisir entre JDO et les EJB ? Tout dépend de votre objectif. S'il se limite à la persistance d'objet, JDO est le plus adapté car il a été conçu pour cela, et offre dans ce domaine une très bonne performance (cache, optimisations) et souplesse (paramétrage, granualité fine). Si votre objectif est de construire des composants réutilisables dans des applications différentes, les EJB sont les plus adaptés, fournissant divers autres services que JDO n'offre pas (distribution, transactions implicites, sécurité). Le but initial des EJB n'est pas de faire persister des objets mais de fournir un modèle de composant. Pour permettre une bonne réutilisablité des composants, EJB est obligé de fournir une indépendance au niveau persistance.
  • Peut-on mélanger EJB et JDO ? Tout à fait. Un EJB Session ou Entité peut très bien encapsuler des objets JDO persistants, ou effectuer des requêtes JDO.
  • JDO peut-il être utilisé dans un serveur applicatif ? Oui, et c'est en fait décrit dans la spécification JDO. Une implémentation JDO peut fournir un connecteur JCA s'intégrant dans tout serveur compatible J2EE 1.3 ou supérieur.
  • Peut-on faire du SQL avec JDO ? La plupart des implémentations existantes le permettent. En fait une Query JDO peut être paramètrée pour utiliser le langage de votre choix, et pas seulement JDO QL. Lorsque SQL est supporté, c'est aussi souvent en apportant une valeur ajoutée, comme la construction automatique d'objets en fonction d'une clause WHERE, le support de l'héritage, etc.
  • Peut-on précompiler des requêtes JDO ? Oui. De la même manière que les PreparedStatement JDBC sont censées précompiler des requêtes SQL (ce qui n'est en réalité pas supporté par tous les SGBDR), une requête JDO peut être compilée avant une utilisation repétée. Cette compilation s'effectue dans l'implémentation JDO et n'est donc pas dépendante des SGBD sous-jacents. De plus les implémentations JDO utilisent généralement elle-même des PreparedStatements (poolées, etc.).
  • Puis-je utiliser JDO dans une application Web ? Oui. JDO y est d'autant mieux adapté qu'il est prévu pour fournir des identifiants d'objets sous forme de chaînes de caractères (facilement stockable dans des pages et/ou sessions Web) et qu'il supporte les transactions optimistes (potentiellement "longues" en raison du mode déconnecté de l'interaction client/serveur Web et du client think time).
  • Puis-je débugger des classes qui ont été enhancées ? Tout à fait. Un enhancer de byte code modifie les numéros de ligne dans les infos de debogage lorsqu'il enhance le bytecode d'une classe.
  • Quels sont les avantages de JDO par rapport aux entités EJB ? JDO n'offre d'avantages que dans le domaine de la persistance. Si vous avez besoin de composants réutilisables, vous avez besoin des EJB. Dans le cas où vous ne chercher qu'à faire persister des objets, alors JDO se démarque par des fonctionnalités garanties par sa spécification, et non supportées par le standard EJB, telles que le support :
    • de l'héritage, alors que les entités ne le permettent pas (à juste titre en tant que composants réutilisables)
    • d'un groupe de chargement (default-fetch-group) paramétrable, alors que les EJB ne le spécifient pas (généralement l'ensemble des champs est chargé)
    • d'un langage (JDO QL) permettant d'interroger des collections (myCollection.contains(var1) && var1.otherCollection.contains(var2) && var2 == xxx par exemple), alors que EJB QL ne permet pas de requêtes de ce type (field.collection.field est interdit). Cependant depuis JDO 2.0 un certain rapprochement entre ces deux langages a été décidé et JDO QL pourra être un langage utilisable dans EJB 3.0.
    • du support des transactions optimistes, alors que les EJB ne supportent que les transactions du SGBD (on doit alors implémenter l'optimiste à la main)
    • du paramétrage du comportement en cas de commit() ou de rollback() de transaction (paramétrage propriétaire pour les EJB quand c'est possible)
    • du paramétrage du cache (possibilité de l'ignorer) alors que les EJB ne spécifie par de tel comportement
    • de la possibilité d'effectuer des transactions sur des objets non persistants (impossible ou à implémenter manuellement de manière très compliquée avec des EJB).

FUD

Du FUD a parfois été présenté sur JDO.

  • JDO ne couvre pas telle ou telle fonctionnalité. En tant que standard, JDO ne peut demander aux éditeurs de tout supporter. Il se limite donc à un plus-petit-commun-dénominateur acceptable, définissant des fonctionnalités optionnelles. Il convient donc d'examiner ce que fournissent les implémentations JDO, et non la spécification du standard seule. A côté de cela, la plupart des fournisseurs d'implémentation JDO implémentent bien plus que la spécification, en proposant de nombreuses fonctionnalités (mapping de l'héritage, multi-tables) ou optimisations (cache partagé, distribué) au-delà de ce que définit le standard lui-même.
  • JDO n'est pas supporté par les plus grands acteurs du marché. JDO, déjà API standard implémentée par une quinzaine d'éditeurs, est pressenti pour être intégré à J2EE 1.5. De ce fait l'ensemble des éditeurs de serveurs applicatifs devront en fournir une implémentation. Le serveur JBoss a par exemple déjà commencé le travail. Des acteurs importants comme Oracle ou même SAP ont commencé à travailler sur une implémentation JDO.
  • JDO est trop jeune. La spécification JDO est issue d'une réflexion d'acteurs important du domaine tels que IBM, Ericsson, IONA, Informix, Object People, Oracle, Rational, SAP, Secant, Sun et Versant. Elle a notamment bénéficié des retours d'expérience du standard CMP des EJB, implémenté par Craig Russell, expert du groupe JDO. La dernière version de JDO est la 2.0, adoptée fin .
  • Le mapping O/R n'est pas standardisé. Il l'est depuis JDO 2.0.
  • JDBC suffit
    • Personne n'a besoin de supporter autre chose que le SGBDR du projet : C'est à peu près la même chose que de dire que personne n'a besoin de JDBC, et que l'on a pas besoin de connaître autre chose que l'API bas-niveau du SGBDR (ce que disaient les développeurs comme argument contre SQL quand il est apparu à la fin des années 1980s, ou contre Java qui était décrit comme sans avenir par rapport aux performances du C ou du C++ à la fin des années 1990s). En réalité c'est un investissement à plus large échelle que d'utiliser JDO : élever le niveau de la gestion de la persistance (supportant de multiples bases relationnelles, et d'autres supports si besoin). D'autres standards, comme SDO, ont identifié ce besoin d'abstraction de la source de données.
    • Je peux aller plus/aussi vite en JDBC : C'est l'évidence en théorie, puisqu'une implémentation JDO va utiliser du SQL pour accéder à des SGBDR. Dans la réalité, c'est autre chose. Aller aussi vite qu'une implémentation JDO connaître aussi bien les optimisations pour chaque SGBD que ne le connaît l'éditeur JDO, mais aussi implémenter divers niveaux de cache ou d'optimisations symboliques. Par exemple objet.getCollection().add(e) ne devrait générer qu'une insertion et ne pas charger la collection pour rien. Enfin, il est une autre vitesse où JDBC n'a pas non plus forcément l'avantage : celle du développement. Les projets sont de plus en plus complexes (et donc coûteux) et demandent plus d'abstraction pour obtenir des temps de développement -- et des possibilités fonctionnelles -- acceptables. Allez donc implémenter en JDBC la requête JDO QL : manager.department.employees.contains (anEmployee) && ((Woman) anEmployee).husband == this par exemple. JDO saura le faire de la manière la plus optimisée possible, sans que le développeur perde du temps à descendre au niveau du support de persistance aux paradigme, API et specificités différentes du niveau applicatif.

Notes

  • Peuvent être utilisés par les EJB (sessions, entités CMP ou BMP) comme classes de persistance.
  • Standard JDO
    Logiciel Standard JDO Commentaire
    Version 1 2
    Release 0 0
    Domaine Technologie Maintenance 0 1
    Inclus dans J2EE Package optionnel, intégrable via JCA.
    Requêtes JDOQL Oui JDO Query Language
    Appel de fonctions Traitement sur le résultat (collection.size(), etc.) ou Query en langage SQL query.setResult (min ou max ou sum ou avg ou manipulation de chaînes)
    Appel de méthodes Non object1.compute() > objet2.getMax()
    Transactions Distribuées Oui
    Optimistes Optionnel JDOOptimisticVerificationException
    Déconnectées Non Oui Travail sur des instances détachées (client distant) puis reconnection.
    Ecriture non transactionnelle Optionnel
    Lecture non transactionnelle Optionnel
    Environnement géré Oui
    non-géré Oui
    Stockage SGBDR mapping via extensions des métadonnées JDO mapping normalisé Oracle, MySQL, etc.
    SGBDO Oui Versant par exemple
    Non persistant Optionnel Transactions en mémoire
    Instance Identité Durable Datastore Oui Fournie par l'implémentation JDO, masquée dans l'objet
    Applicative Composée Composée ou simple
    Non durable Optionnel
    Changement Optionnel
    Transactionnelles Transitoire Optionnel
    Persistante Oui
    Non transactionnelles Transitoire Oui
    Persistante Optionnel
    Types Simples Booléens boolean java.lang.Boolean
    Entiers byte short int long java.lang.Byte java.lang.Short java.lang.Integer java.lang.Long java.math.BigInteger
    Flottants float double java.lang.Float java.lang.Double java.math.BigDecimal
    Objet java.lang.Object et dérivés null supporté
    Chaîne java.lang.String char java.lang.Character
    Internationalisation java.util.Locale
    Date java.util.Date
    Tableaux Primitifs boolean[] byte[] short[] int[] long[] char[] float[] double[]
    Array Optionnel
    Dictionnaires Map Optionnel
    HashSet Oui
    HashMap Optionnel
    TreeMap Optionnel
    Hashtable Optionnel
    Collections Collection Optionnel
    Listes List Optionnel
    ArrayList Optionnel
    LinkedList Optionnel
    Vector Optionnel
    Ensembles Set Optionnel
    TreeSet Optionnel
    Bidirectionnelles Non spécifié Oui
    Supression en cascade Non spécifié Oui Cascade delete

Exemples

Un exemple de classe persistante est n'importe quelle classe POJO.

Un exemple de code JDO est :

import javax.jdo.*;

 // Code code suppose que pm réference un PersistenceManager et qu'il y a un contexte transactionnel en cours
    Employee jerome = new Employee ("Jérôme", "Beau");
 Address jeromeAddress = new Address("71 rue Desnouettes", "75015", "Paris");

      jerome.setAddress (jeromeAddress);

 Transaction tx = pm.currentTransaction();

      tx.begin();
 {
 ProjectId lidoProjectId = new ProjectId ("LiDO", 3.1); // Identifiant métier du projet

      Project lidoProject = pm.getObjectById (lidoProjectId, true); // Récupère le projet en base


 jerome.getProjects().add (lidoProject);
 lidoProject.getWorkers().add (jerome);
 pm.makePersistent (jerome);
      // Rend aussi jeromeAddress persistant, de proche en proche (clôture transitive)

}
 tx.commit(); // Ecrit les jerome et jeromeAddress en base
    tx.begin();
 {
 // Récupère les projets dont le nom commence par "L", dont les collaborateurs et travaillent à Paris ou qui contiennent le collaborateur jerome

  Query query = pm.newQuery (Projet.class, "workers.contains(aPeople) && aPeople.address.city == someCity && name.startsWith(\"L\") || aPeople == somePeople");

      myQuery.declareVariables  ("Employee aPeople");
 myQuery.declareParameters ("String someCity, Employee somePeople");
 myQuery.setOrdering ("name ascending, manager.name ascending"); // Trie les résultat par nom de projet puis éventuellement par nom du manager du projet

      Collection foundProjects = (Collection) myQuery.execute (jerome, "Paris"); // Exécute la requête avec les arguments suivants
 Iterator foundProjectsIterator = foundProjects.iterator();
 while (iter.hasNext()) {
 Project aFoundProject = (Project) foundProjectsIterator.next();

     // Utilise projet
 }

      myQuery.close (result);
 }
 tx.commit();

      pm.close();
 

Un exemple de descripteur JDO standard est :


    <!DOCTYPE jdo SYSTEM "jdo.dtd">
      
        
          
            
          
          
            
            
            
          
      

      

      

      

      

      


      


      
Implémentations JDO
Fournisseur Exadel Object Frontier OSS Object Industries Versant Solarmetric Xcalia (LIBeLIS) ObjectDB Software (Apache) Jakarta SignSoft (Apache)
Produit Exadel JDO Frontier Suite for JDO JPOX JRelay JDO Genie

Judo / enJin

Fast Objects Kodo JDO LiDO ObjectDB OJB intelliBO TJDO
Version 3 1 2 j2 2 3 3 2
Domaine Technologie Release 0 1 0 5 1 0
Standard JDO Version 1.0 1.0 2.0-- 2.0--
Cache Partagé / niveau 2 Entre PM Oui Oui Active Java Cache Oui lido.cache.mode=shared CacheConfiguration. setUseNTXCache (true)
Entre PMF JMS ou TCP

lido.cache.mode=shared
lido.cache.group= myMultiplePmfGroup

(si même JVM)

Agrafage d'objets DataCache.pin(objectId) pin(object) ou lido.cache.classStrategy (myClassName)= pinned
Par classe Extension cache-strategy=yes|all d'une classe Extension can-cache =true d'une classe (défaut) Oui CacheConfiguration. setUseNTXCache (false)
Distribué Version entreprise Oui JMS Via cache listeners plugins, JDOGenie Servers Non kodo.DataCache via DataRepository API JMS, TCP
JCache Non Oui via DataRepository API
Pluggable Oui Oui
Tangosol Oui kodo.DataCache: tangosol(TangosolCacheName=kodo, TangosolCacheType=distributed) via DataRepository API
Exclusif lido.cache.exclusive=true
Evénements kodo.event.RemoteCommitProvider: jms ou tcp lido.cache.CommitListeners= com.acme.MyCommitListener
Requêtes JDO QL Extensions String toLowerCase() stringContains() caseInsStarts() caseInsEnds() caseInsContains() toLowerCase() toUpperCase() Non charAt() length() startsWith(substr,pos) substring(begin,end) toLowerCase() toUpperCase()
Map containsKey(key) contains(value) isEmpty() containsKey(key) containsValue(value) containsKey(key) containsValue(value) Non
Curseurs Mono-transaction randomAccess= true com.solarmetric.kodo. ResultListProperties cursor= basic
Cross-transactions cursor= cross-pm
Taille paramétrable fetch-size=n LIDOHINT
Cache des résultat kodo.QueryCache: CacheSize=n Oui
Chargement Grappe fetch-group=fields Eager Fetching
Personnalisable Fetch groups
load= dfg| true JDOQLQuery. addFetchGroupAttribute ("myAttribute");
SQL Libre Oui Oui Non sqlEmbed

query = pm.newQuery ("sql")
query.setFilter ("where ...")
query.setFilter ("select ...")

Non SQLQuery query = QueryFactory. newSQLQuery() Oui
Procédures stockées query.setFilter ("call ...")
Transactions Distribuées (XA) Oui Oui Non Oui Oui Oui
Optimistes Versionnage Oui Oui Oui Oui N° version, Ttimestamp Non Non Extension jdbc-version-ind" value="version-number" champ JDO sélectionné (lido.optimistic.class.MyClass =selected sur champ int ou Date) Oui Extension optimistic-lock (timestamp ou version)
Champs modifiés Oui Tous, champs modifiés, champ / classe Non
Ecriture non transactionnelle Non Non Oui Non Non Oui Oui Oui
Lecture non transactionnelle Oui Oui Oui Non Non Oui Oui Oui
Environnement Intégration serveurs applicatifs Weblogic, WebSphere, JBoss, Orbix E2A, Oracle 9i, HP AS, Orion, JRun Java Connectors

Via MBeans (WLS 7.0, JBoss 2.4, 3.0, WAS 5.0)

Non DataSource (Jboss, WebLogic, WenSphere, SunOne, JRun, Borland)
Java Connectors Java Connectors
Attacher/détacher (JDO 2.0) Oui Oui
Stockage SGBDR CloudScape Non Oui Non Non Non Non 4.0.6 Oui Non Non 4.0.6, 5.0.9
DB2 7.1 Oui 07.02.0000 Oui Non Oui 7.2 Oui Non Oui 7.2.3
FireBird Non Non Non 1.0.2 Non Non Non Oui Non Non 1.0.0.796
HSQL DB Non Non Non Non Non Non 1.6 Oui Non Non Non
Ingres Non Non Non Non Non Non Non Oui Non Non Non Non
Informix Non Oui Non 9 Non Non Oui Oui Non 7.31 Non
InstantDB Non Non Non Non Non Non 3.26 Oui Non 3.14 Non
Interbase Non Non Non 6 Non Non Non Oui Non Non Oui
JDataStore Non Non Non Oui
MS Access Non Oui Non Non Non Non Oui Oui Non Non Non
MS FoxPro Non Non Oui
MS SQL Server 8.0 Oui 7.0 7.0 Non Oui 8.0 Oui Non Oui 7.0 SP4, 2000 SP2
McKoi Non Non Non Non Non Non Non Oui Non Non Non
MySQL Non Oui Non 3.23.49, 4.0.12 Non Non 3.23 Oui Non Oui 3.23.55-max
Oracle 8.1, 9.2 Oui 8.1.7 8.1.7 Non Oui 8.1-9.1 Oui Non 8.1.7 8.1.7.4.0
Pervasive SQL Non Non Non Non Non Non Non Non Non Oui Non
PointBase Non Oui Non 4.5 Non Non 4.2 Oui Non Non Non
PostgreSQL Non Non 7.1.3 7.3.1 Non Non 7.2.1 Oui Non Oui 7.2.1, 7.3.1, 7.3.2-1
Progress Non Non Non Non Non Non Non Non Non Oui Non
SAP DB Non Non Non 7.3 Non Non Non Non Oui 7.4.3 Build 010-120-035-462
Sybase Non Oui Non 11.9.2, 12.5 Non Non 12.5 Oui Non Oui Non
Unisys Non Non Non Non Non Non Non Oui Non Non Non Non
SGBDO Versant Non Non Non Non Non Oui Non Oui Oui Non Non Oui Non
Autre Propriétaire Non Non Non Non FDB ObjectDB
Autre Via dictionnaire fourni Non
XML Non Non Non Non Non Oui Non Oui
Instance Identité Durable Datastore Oui Oui Oui Oui Oui Oui Oui Oui
Applicative Oui Oui Oui Génération automatique de classe Non Non Oui Génération automatique de classe et de valeurs Non
Personnalisé Oui OidProvider
SGBD Champs identité, séquences, tables
Non durable Oui Non Non Non Non Oui Non
Changement Non Non Non Non Non Oui Non
Transactionnelles Transitoire Oui Oui Oui Oui
Persistante Oui Oui Oui Oui
Non transactionnelles Transitoire Oui Oui Oui
Persistante Oui Oui Oui Oui
Détachement/attachement Oui
Collections Nulles Oui Oui Non Non Oui Oui Non Oui
Tableaux Array[] Non Oui Oui Oui Oui Oui Oui Oui Oui Non
int[][], byte[][] Oui
int[][][], byte[][][] Oui
Dictionnaires Map Non Non Oui Oui Oui Oui Oui Oui Oui Oui
HashSet Oui Oui Oui Oui Oui Oui Oui Oui Non Non
HashMap Non Oui Oui Oui Non Oui Oui Oui Oui Non
TreeMap Non Oui Oui Non Non Non Oui Oui Oui Non
Hashtable Non Oui Oui Oui Oui Non Oui Oui Oui Non
Listes List Oui Oui Oui Oui Oui Oui Oui Oui Oui Non
ArrayList Oui Oui Oui Oui Oui Oui Oui Oui Oui Non
LinkedList Oui Oui Oui Oui Oui Oui Oui Oui Oui Non
Vector Oui Oui Oui Oui Oui Non Oui Oui Oui Non
Ensembles Set Oui Oui Oui Oui Oui Non Oui Oui Oui Oui
TreeSet Oui Oui Oui Non Oui Non Oui Non Oui Non
Développement Outils Mapping graphique Oui Non LiDO Studio JDO Explorer
Navigateur de modèle Non Navilis
Génération de schéma Oui Oui Oui DefineSchema, LPM schemagen
Retro- ingénierie de schéma Oui Pour XML ClassGenerator
Evolution de schéma Oui DefineSchema
Intégration IDE JBuilder Non Non 6 Oui Non Oui
TCC Non Non Non Non Lido 1.4 Oui
Sun ONE Studio Non Oui Oui Non Non
Eclipse / WSAD Non Oui Non Oui 2.x (LiDO Studio) Non
API Métadonnées Oui
Javadoc XDocLet JDODocLet
Taglib Non Oui
Suppressions en cascade Non Extension dependent du champ collection Extensions dependent, value-dependent, key-dependent et element-dependent Automatique pour collections en reverse , sinon en partie via l'extension sql-delete-behavior (sinon InstanceCallback) Extension cascade-delete du champ
Mapping Classe Plusieurs tables Non Oui Extension table du champ collection. Clés primaires différentes supportées Oui
Héritage Vertical Oui Non Oui <inheritance-strategy type="per-class"> Extension inheritance d'une classe
Horizontal Non Non Oui <inheritance-strategy type="per-concrete-class"> (défaut) Non
Autre Possible
Plat / Filtré Non Oui Oui Oui <inheritance-strategy type="per-hierarchy"> Oui
Relations 1-1 Oui Oui
Inversée Oui
1-n Table de liaison Oui Oui Oui Oui Oui (défaut)
Inversée (non ordonnée) Extension inverse du champ collection Extension inverse du champ collection <associate field="f" to-column="c">
n-m Table de liaison Oui Oui Oui Oui Oui
Inversée (non ordonnée) Oui Extension inverse du champ collection Oui Non
Champs Convertisseurs Oui JdbcConverter custom-mapping=ClassMapping, extension column-length CustomMapper, CustomizableMapper
DataStore Multiples Non Extension datastore d'une classe Non Non
  • HYWY Software PE:J The Productivity Environment for Java
  • OrientTechnologies Orient

Limitations

  • Les objets doivent être locaux en environnement non géré.
  • l'état des objets ne peut être représenté que par l'ensemble des champs de ces objets. Par conséquent certains types d'objets disposant d'un état non entièrement Java (System, Thread, Socket, File) ne peuvent être rendus persistants via JDO (ni dans la plupart des autres solutions de persistance).
  • Les objets doivent être PersistenceCapable (implicitement ou explicitement) avant leur chargement en mémoire.
  • Support des collections limité à celles connues (de J2SE typiquement)
  • Pas de PGC (Persistent Garbage Collection)
  • Voir également le débat entre Carl Rosenberger (directeur du projet de persistance objet DB40) et Craig Russel (directeur de la spécification JDO).
  • Si un objet JDO hérite d'un objet non JDO
    • ce dernier doit au moins avoir un constructeur par défaut protégé
    • on doit redéfinir et utiliser les accesseurs aux champs hérités

Références