{"partition": "head_middle", "source_domain": "blog.ippon.fr", "digest": "sha1:PKZD3QSIRT2GUFMZE6QGHUUMWB32X3VC", "path": "/lustre/fsn1/projects/rech/qgz/uzq54wg/processed_redpajama/base_processing/output/fr/2014-15/000_00027.parquet"}
Back-end
Front-end
Agilité
Le Blog d'Ippon Technologies JPA : une magie qui se mérite (retour aux sources de JPA)
Par Antoine SABOT-DURAND CDI, EJB 3.1, Java EE, JPA Cet article fait partie d’une série sur les technologies incluses dans Java EE 6. Vous pouvez également lire l’article d’introduction de cette série : Java EE 6 ici et maintenant et celui sur JSF : JSF je t’aime, moi non plus
L’une des technologies les plus populaires dans le monde Java EE est sans aucun doute JPA. Il suffit de voir le nombre de livres et d’articles sur le sujet. Toutefois, si JPA est très répandu, il s’agit aussi de l’une des spécifications Java EE les moins bien maîtrisées par les développeurs et donc une source récurrente d’échecs des projets. Fort de ce constat je ne vais pas m’apesentir sur les nouveauté de JPA 2.0 dans ce post (en dehors de l’API criteria, celles-ci sont pluôt à la marge) pour me permettre de faire un retour aux sources sur JPA qui pourra profiter à certains. Ceux qui pensent maîtriser ces concepts pourraient être quand même intéressés par la fin de la’article qui traite de l’extended persistence context et de ses mérites.
Vous aimerez aussi
Java EE 6 ici et maintenant !
Ippevent Arquillian : Le film !
Les rendez-vous manqués de Spring (une courte histoire de Java EE)
Ippon Technologies est partenaire PrimeFaces
Cet article fait partie d’une série sur les technologies incluses dans Java EE 6. Vous pouvez également lire l’article d’introduction de cette série : Java EE 6 ici et maintenant et celui sur JSF : JSF je t’aime, moi non plus
Une “magie” complexe
La popularité de JPA et les échecs que cette techno engendre sont probablement liées au mélange de magie, de concepts compliqués qu’elle camoufle et de dissimulation de ces concepts au sein de frameworks destinés à faciliter son utilisation. La magie et les raccourcis offert par Spring (entre autres) permettent de se lancer dans l’utilisation de l’outil sans avoir besoin de trop comprendre les couches sous-jacentes. Lorsque l’on arrive dans des cas concrets qui posent des problèmes, une grande partie des développeurs désinvestissent l’outil en critiquant ses limitations sans chercher à creuser plus avant. Parce que JPA nous fait sortir du confort du code pour aller nous battre avec des notions parfois mal digérés de gestion de transaction et base de données, il reste une énigme pour beaucoup. Certains développeurs pensent que le concept d’ORM en général et JPA en particulier permet de négliger SQL et les mécanismes bas niveau d’échange avec la BDD en les ramenant au rang de technologies inférieures. En pensant cela ils commettent une erreur : JPA rend l’utilisation de ces technologies plus facile et puissante mais ne nous permet pas des les occulter totalement. Il est un facilitateur pas une technologie de substitution.
Les 4 piliers de JPA
JPA s’inscrit autour de ces 4 notions fondamentales :
Les entités
Les Persistence Units (au runtime on les manipulera via la classe PersistenceManagerFactory)
L’Entity Manager (ou persistence manager)
Les transactions
Le schéma ci-contre illustre le fonctionnement de JPA et comment ces 4 éléments fonctionnent ensemble. Pour synthétiser :
La Persistence Unit organise les meta données qui définissent le mapping entre les entités et la base
La Persistence Manager Factory récupère ces metas données de la Persistence Unit et les interprètent pour créer des Persistence Manager
Le Persistence Mangager gère les échanges entre le code et la base de donnée, c’est à dire le cycle de vie des entités
Enfin, le travail du Persistence Manager est englobé dans une Transaction. Cette dernière peut éventuellement gérer les opérations de plusieurs Persistence Managers comme un traitement unitaire.
Sans faire un cours exhaustif, il parait intéressant de faire un point sur les concepts clés liés à chacune de ces notions clés
Les transactions ne faisant pas stricto sensu partie de JPA, mais étant une composante indispensable au fonctionnement et donc à la compréhension de cette technologie, il est intéressant de commencer notre tour d’horizon par un rappel sur les concepts liés au transactionnel. Les transactions sont en effet aussi importantes que les mécanismes de persistence décrits plus loin. Sans elles les données échangées avec la base risqueraient d’être corrompues ou incohérente. C’est pourquoi il est important de vérifier que le périmètre des transactions soit bien défini lors de l’interaction de votre code avec la base de données.
L’objet de ce post n’est pas de faire un cours magistral sur le transactionnel, mais il me semble intéressant de rappeler quelques concepts de base puisqu’on parle de base de données et de persistence.
Retour sur les différentes APIs transactionnelles
Une transaction est un regroupement d’instructions SQL effectuant un traitement fonctionnel atomique (par exemple l’ajout d’un article dans un panier d’achat accompagné d’une décrémentation des stock pour la référence concernée). Ce regroupement est orchestré à l’aide d’instructions SQL dédiées comme : BEGIN, COMMIT ou ROLLBACK. Bien sûr, si on ne souhaite pas agir à si bas niveau on aura plutôt recours en Java à des API chargées d’automatiser la gestion des transactions pour nous. A cette fin, nous disposons de trois possibilités :
Les transactions gérées par JDBC
Les transactions de type Resource-local
Les transactions gérées par JTA
JDBC est hors sujet pour cet article, gardons juste à l’esprit que les appels JDBC sont toujours exécutés par défaut dans une transaction. Vous pouvez décider de gérer vous-même le début et la fin de celle-ci avec setAutocommit(false) dans une java.sql.Connection puis lorsque vous le souhaitez, lancer un commit() ou un rollback() à partir de cette même connexion. La gestion de la transaction reste simpliste et ne permettra pas de l’utiliser correctement au niveau de l’ORM, mais elle est présente.
Les transactions de type Resource-Local sont elles gérées à un niveau supérieur, celui du Persistence Manager. Ce type de transaction rencontré dans Spring est axé sur la base et permet de gérer le cycle de vie de la transaction au niveau de l’ORM et d’automatiser facilement certains comportement (Rollback systématique en cas d’exception par exemple).
Enfin, les transactions JTA sont gérées par le container Java EE et permettent de travailler avec plusieurs datasources facilement. JTA est une spec Java EE, aussi on sera amené à l’utiliser dès qu’on voudra effectuer des tâches transactionnelles avec les EJB.
Pour conclure, gardez à l’esprit que la base de données ouvre et ferme une transaction à chaque opération si aucune démarcation de transaction n’est spécifiée dans votre code. C’est ce qui s’appelle la transaction implicite. Donc quand vous négligez de gérer les transactions, la base s’en charge à votre place à chaque instruction SQL y compris les lectures. Le mécanisme de la transaction étant assez coûteux, il est donc important d’opérer cette démarcation de manière explicite ne serait-ce que pour améliorer les performances de vos lectures.
Les entité et le Mapping
JPA permet donc d’associer des objets dans notre code à des données dans une ou plusieurs bases. Les metas données du mapping (sous forme d’annotations) apportent la souplesse indispensable qui évite d’avoir un modèle de données mémoire totalement calqué que le modèle de donnée relationnel dans la base. On pourra ainsi gérer les colonnes associées à un champ (avec @column), créer une entité sur plusieurs tables (avec @SecondaryTable) ou gérer des champs ne devant pas être stockés (avec @Transient). Bien sûr la magie n’est pas absolue et il peut arriver un moment où votre structure de base de données est trop complexe pour assurer un mapping satisfaisant et où le choix de JPA peut commencer à être remis en cause. Une notion qu’il est capitale de comprendre est la persistance transitive : les associations entre entités avec les fameux @OneToOne, @OneToMany ou @ManyToMany. Le débutant en JPA rencontrera très vite ses premiers problèmes avec ces concepts. Soit parce que les associations déclencheront des chargements en cascade et créeront des grappes d’objets monstrueuses en mémoire, soit parce qu’il aura eu recours au mécanisme de Lazy loading qui peut devenir un cauchemar si on ne maîtrise pas le cycle de vie des entités et les concepts liés au transactionnel. On se reportera à la documentation des