Quelle est la différence entre JPA, Hibernate et EclipseLink

Lorsque les gens sont nouveaux sur JPA, Hibernate ou EclipseLink, ils sont souvent confus quant à la différence entre eux et celle qu’ils doivent utiliser dans leur projet. Si vous êtes l’un d’entre eux, ne vous inquiétez pas. C’est beaucoup plus facile qu’il n’y paraît.

Jetons d’abord un coup d’œil à la spécification JPA.

API de persistance Java (JPA)

JPA est une abréviation qui signifie API de persistance Java. C’est une spécification qui fait partie de Java EE et définit une API pour les mappages objet-relationnels et pour la gestion des objets persistants. Vous pouvez utiliser cette API dans les environnements Java SE et Java EE.

La spécification est actuellement disponible dans la version 2.2. Vous pouvez télécharger le document à l’adresse https://jcp.org/en/jsr/detail?id=338. Le jar de l’API est disponible aux coordonnées Maven suivantes :

<dependency> <groupId>javax.persistence</groupId> <artifactId>javax.persistence-api</artifactId> <version>2.2</version></dependency>

JPA lui-même ne fournit aucune classe d’implémentation. Le pot API contient simplement un ensemble d’interfaces que vous pouvez utiliser pour implémenter votre couche de persistance. Mais vous ne pouvez pas utiliser JPA seul. Vous avez besoin d’un fournisseur JPA qui implémente la spécification. Plusieurs options sont disponibles. Les plus populaires sont Hibernate et EclipseLink. Mais plus à ce sujet plus tard.

Jusqu’à récemment, JPA était géré et développé par un groupe d’experts suivant le Java Community Process (JCP). Cela a changé lorsque Oracle a annoncé le transfert de toutes les spécifications Java EE à la Fondation Eclipse. Nous sommes maintenant au milieu du processus de transition et un nouveau processus de spécification sera bientôt défini.

Ce qui est défini par la spécification JPA

La spécification définit la plupart des fonctionnalités que j’ai expliquées dans les tutoriels et vidéos de ce site. Vous pouvez les utiliser avec toutes les implémentations JPA conformes.

Jetons un coup d’œil à certains des plus importants.

Amorçage et mappages d’entités de base

Avant de pouvoir commencer à utiliser JPA, vous devez l’ajouter à votre projet, configurer une unité de persistance, mapper des entités sur vos tables de base de données et l’amorcer. Vous savez probablement déjà comment faire cela, et je l’ai expliqué en détail dans mon article Pour commencer avec Hibernate.

Alors, sautons cette partie ici et parlons des fonctionnalités les plus intéressantes.

Associations de mappage

JPA ne vous permet pas seulement de mapper des attributs d’entité simples aux colonnes de base de données, mais il vous permet également de mapper des associations entre les tables de base de données aux attributs d’entité.

@Entitypublic class Review {...@ManyToOneprivate Book book;...}

Cela rend souvent votre modèle d’entité très confortable à utiliser car il vous suffit d’appeler une méthode getter sur une entité pour charger les entités associées. En arrière-plan, le fournisseur de persistance effectue toutes les opérations de base de données requises pour récupérer et gérer l’association.

Aussi confortable à utiliser que cela puisse être, cette fonctionnalité cause souvent des problèmes de performances. Avant de commencer à modéliser des associations entre vos entités, assurez-vous de comprendre l’effet des types de récupération de JPA pour éviter les problèmes de sélection n+1.

JPQL et requêtes natives

JPA définit son propre langage de requête, appelé JPQL. Il est similaire à SQL mais vous permet de définir des requêtes basées sur le modèle de domaine mappé au lieu du modèle de table de la base de données.

L’extrait de code suivant montre une requête JPQL simple. Vous pouvez définir une requête ad hoc en appelant la méthode createQuery sur l’em EntityManager. Comme vous pouvez le voir, la syntaxe ressemble beaucoup à SQL. Si vous n’êtes pas familier avec JPQL, veuillez consulter mon guide JPQL dans lequel j’explique sa syntaxe et ses capacités en détail.

TypedQuery<Book> q = em.createQuery("SELECT b FROM Book b WHERE b.id = :id", Book.class);q.setParameter("id", 1L);Book b = q.getSingleResult();

Lorsque vous exécutez une telle requête, votre fournisseur de persistance interprète l’instruction JPQL et génère une requête SQL pour celle-ci. Ce faisant, le fournisseur de persistance adapte la requête au dialecte SQL spécifique à la base de données et améliore la portabilité de votre application.

Malheureusement, cela vous limite également aux fonctionnalités de requête définies par la spécification ou supportées par votre fournisseur de persistance. Cet ensemble de fonctionnalités est nettement plus petit que celui proposé par SQL et n’inclut aucune fonctionnalité de base de données propriétaire.

Mais cela ne signifie pas que vous ne pouvez pas utiliser de requêtes avancées ou complexes avec JPA. Il est conçu comme une abstraction qui fuit et vous permet d’exécuter des requêtes SQL natives. Ceux-ci ne sont pas analysés par votre fournisseur de persistance et vous pouvez utiliser toutes les fonctionnalités prises en charge par votre base de données. Mais sachez que cela pourrait affecter négativement la portabilité de votre base de données.

L’exécution d’une requête native est assez simple. Il vous suffit d’appeler la méthode createNativeQuery au lieu de la méthode createQuery sur votre EntityManager avec une requête SQL native.

Query q = em.createNativeQuery("SELECT * FROM book b WHERE id = :id", Book.class);q.setParameter("id", 1L);Book b = (Book) q.getSingleResult();

Types de données personnalisés

La spécification JPA définit le mappage pour la plupart des types standard sans vous limiter à eux. Depuis JPA 2.1, vous pouvez facilement prendre en charge les types de données personnalisés avec un AttributeConverter. Il vous suffit d’implémenter l’interface AttributeConverter et d’annoter la classe avec une annotation @Converter.

Voici un exemple de convertisseur d’attributs qui définit un mappage personnalisé pour mon énumération AutherStatus.

@Converter(autoApply = true)public class AuthorStatusConverter implements AttributeConverter<AuthorStatus, String> {Logger log = Logger.getLogger(AuthorStatusConverter.class.getSimpleName());@Overridepublic String convertToDatabaseColumn(AuthorStatus status) {switch (status) {case NOT_PUBLISHED:logDbConversion(status, "N");return "N";case PUBLISHED:logDbConversion(status, "P");return "P";case SELF_PUBLISHED:logDbConversion(status, "S");return "S";default:throw new IllegalArgumentException("AuthorStatus not supported.");}}@Overridepublic AuthorStatus convertToEntityAttribute(String dbData) {switch (dbData) {case "N":logEntityConversion(AuthorStatus.NOT_PUBLISHED, "N");return AuthorStatus.NOT_PUBLISHED;case "P":logEntityConversion(AuthorStatus.PUBLISHED, "P");return AuthorStatus.PUBLISHED;case "S":logEntityConversion(AuthorStatus.SELF_PUBLISHED, "S");return AuthorStatus.SELF_PUBLISHED;default:throw new IllegalArgumentException("AuthorStatus not supported.");}}private void logDbConversion(AuthorStatus status, String dbData) {log.debug("Convert AuthorStatus enum to .");}private void logEntityConversion(AuthorStatus status, String dbData) {log.debug("Convert DB value to AuthorStatus enum .");}}

EclipseLink et Hibernate

Comme je l’ai déjà dit, vous avez besoin d’un fournisseur JPA, si vous souhaitez utiliser la spécification JPA dans votre projet. Il implémente les interfaces telles que définies par la spécification. Les plus populaires sont EclipseLink et Hibernate.

Un avantage de l’API standardisée fournie par JPA est qu’il vous suffit d’ajouter son implémentation au moment de l’exécution et que vous pouvez la remplacer par une autre sans changer de code. L’API standardisée rend EclipseLink et Hibernate interchangeables.

Alors, pourquoi avez-vous besoin de différentes implémentations ?

Les implémentations JPA sont gérées par des équipes indépendantes, et vous pouvez choisir celle qui offre les meilleures performances ou le meilleur support pour votre pile d’applications et de technologies. Ils se différencient également en fournissant des fonctionnalités supplémentaires non standard. Ceci est souvent utilisé pour stimuler l’innovation. La fonctionnalité propriétaire populaire d’aujourd’hui pourrait être la première étape vers le prochain ajout à la norme JPA. L’utilisation de l’une de ces fonctionnalités propriétaires rend évidemment beaucoup plus difficile le remplacement d’une implémentation JPA spécifique.

EclipseLink

EclipseLink est l’implémentation de référence de JPA et implémente la version 2.2 de JPA. C’était l’un des premiers projets à faire partie d’EE4J.

Le moyen le plus simple d’ajouter EclipseLink à votre projet est d’utiliser les coordonnées Maven suivantes.

<dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>eclipselink</artifactId> <version>2.7.1</version></dependency>

Fonctionnalités propriétaires intéressantes

En plus des fonctionnalités définies par la norme JPA, EclipseLink propose également plusieurs fonctionnalités propriétaires intéressantes, telles que:

  • Gestion des événements de modification de base de données
  • Unités de persistance composites pour mapper des entités à des tables dans plusieurs bases de données
  • Prise en charge de la multi-location

Hibernate

Hibernate est l’implémentation très populaire de la spécification JPA de Red Hat. Il implémente presque toutes les fonctionnalités définies par JPA 2.2 et publiera bientôt une version entièrement conforme.

La dépendance Maven suivante ajoute Hibernate à votre projet.

<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-core</artifactId><version>5.1.11</version></dependency>

Fonctionnalités propriétaires intéressantes

Similaire à EclipseLink, Hibernate fournit un tas de fonctionnalités propriétaires intéressantes, telles que:

  • Prise en charge étendue des identifiants naturels
  • Chargement de plusieurs entités par leur clé primaire
  • Gestion des horodatages de création et de mise à jour
  • Rejoindre des entités non associées dans des requêtes
  • Prise en charge de la multi-location

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.