Chapitre 24. Meilleures pratiques

Découpez finement vos classes et mappez les en utilisant <component>.

Utilisez une classe Adresse pour encapsuler Rue, Region, CodePostal. Ceci permet la réutilisation du code et simplifie la maintenance.

Déclarez des propriétés d'identifiants dans les classes persistantes.

Hibernate rend les propriétés d'identifiants optionnelles. Il existe beaucoup de raisons pour lesquelles vous devriez les utiliser. Nous recommandons que vous utilisiez des identifiants techniques (générés, et sans connotation métier).

Identifiez les clefs naturelles.

Identifiez les clefs naturelles pour toutes les entités, et mappez les avec <natural-id>. Implémentez equals() et hashCode() pour comparer les propriétés qui composent la clef naturelle.

Placez chaque mapping de classe dans son propre fichier.

N'utilisez pas un unique document de mapping. Mappez com.eg.Foo dans le fichier com/eg/Foo.hbm.xml. Cela prend tout son sens lors d'un travail en équipe.

Chargez les mappings comme des ressources.

Déployez les mappings en même temps que les classes qu'ils mappent.

Pensez à externaliser les chaînes de caractères.

Ceci est une bonne habitude si vos requêtes appellent des fonctions SQL qui ne sont pas au standard ANSI. Cette externalisation dans les fichiers de mapping rendra votre application plus portable.

Utilisez les variables "bindées".

Comme en JDBC, remplacez toujours les valeurs non constantes par "?". N'utilisez jamais la manipulation des chaînes de caractères pour remplacer des valeurs non constantes dans une requête ! Encore mieux, utilisez les paramètres nommés dans les requêtes.

Ne gérez pas vous même les connexions JDBC.

Hibernate laisse l'application gérer les connexions JDBC. Vous ne devriez gérer vos connexions qu'en dernier recours. Si vous ne pouvez pas utiliser les systèmes de connexions livrés, réfléchissez à l'idée de fournir votre propre implémentation de org.hibernate.connection.ConnectionProvider.

Pensez à utiliser les types utilisateurs.

Supposez que vous ayez une type Java, de telle bibliothèque, qui a besoin d'être persisté mais qui ne fournit pas les accesseurs nécessaires pour le mapper comme composant. Vous devriez implémenter org.hibernate.UserType.Cette approche libère le code de l'application de l'implémentation des transformations vers / depuis les types Hibernate.

Utilisez du JDBC pur dans les goulets d'étranglement.

Dans certaines parties critiques de votre système d'un point de vue performance, quelques opérations peuvent tirer partie d'un appel JDBC natif. Mais attendez de savoir que c'est un goulet d'étranglement. Ne supposez jamais qu'un appel JDBC sera forcément plus rapide. Si vous avez besoin d'utiliser JDBC directement, ouvrez une Session Hibernate et utilisez la connexion SQL sous-jacente. Ainsi vous pourrez utiliser la même stratégie de transation et la même gestion des connexions.

Comprendre le flush de Session.

De temps en temps la Session synchronise ses états persistants avec la base de données. Les performances seront affectées si ce processus arrive trop souvent. Vous pouvez parfois minimiser les flush non nécessaires en désactivant le flush automatique ou même en changeant l'ordre des opérations menées dans une transaction particulière.

Dans une architecture à trois couches, pensez à utiliser saveOrUpdate().

Quand vous utilisez une architecture à base de servlet / session bean, vous pourriez passer des objets chargés dans le bean session vers et depuis la couche servlet / JSP. Utilisez une nouvelle session pour traiter chaque requête. Utilisez Session.merge() ou Session.saveOrUpdate() pour synchroniser les objets avec la base de données.

Dans une architecture à deux couches, pensez à utiliser la déconnexion de session.

Les transactions de bases de données doivent être aussi courtes que possible pour une meilleure montée en charge.Cependant, il est souvent nécessaire d'implémenter de longues transactions applicatives, une simple unité de travail du point de vue de l'utilisateur. Une transaction applicative peut s'étaler sur plusieurs cycles de requêtes/réponses du client. Il est commun d'utiliser des objets détachés pour implémenter des transactions applicatives. Une alternative, extrêmement appropriée dans une architecture à 2 couches, est de maintenir un seul contact de persistance ouvert (session) pour toute la durée de vie de la transaction applicative et simplement se déconnecter de la connexion JDBC à la fin de chaque requête, et se reconnecter au début de la requête suivante. Ne partagez jamais une seule session avec plus d'une transaction applicative, ou vous travaillerez avec des données périmées.

Considérez que les exceptions ne sont pas rattrapables.

Il s'agit plus d'une pratique obligatoire que d'une "meilleure pratique". Quand une exception intervient, il faut faire un rollback de la Transaction et fermer la Session. Sinon, Hibernate ne peut garantir l'intégrité des états persistants en mémoire. En particulier, n'utilisez pas Session.load() pour déterminer si une instance avec un identifiant donné existe en base de données, utilisez Session.get() ou un requête.

Préférez le chargement tardif des associations.

Utilisez le chargement complet avec modération. Utilisez les proxies et les collections chargées tardivement pour la plupart des associations vers des classes qui ne sont pas susceptibles d'être complètement retenues dans le cache de second niveau. Pour les assocations de classes en cache, où il y a une extrêmement forte probabilité que l'élément soit en cache, désactivez explicitement le chargement par jointures ouvertes en utilisant outer-join="false". Lorsqu'un chargement par jointure ouverte est approprié pour un cas d'utilisation particulier, utilisez une requête avec un left join fetch.

Utilisez le pattern d'une ouverture de session dans une vue, ou une phase d'assemblage disciplinée pour éviter des problèmes avec des données non rapatriées.

Hibernate libère les développeurs de l'écriture fastidieuse des objets de transfert de données (NdT : Data Transfer Objects) (DTO). Dans une architecture EJB traditionnelle, les DTOs ont deux buts : premièrement, ils contournent le problème des "entity bean" qui ne sont pas sérialisables ; deuxièmement, ils définissent implicitement une phase d'assemblage où toutes les données utilisées par la vue sont rapatriées et organisées dans les DTOs avant de retourner sous le contrôle de la couche de présentation. Hibernate élimine le premier but. Pourtant, vous aurez encore besoin d'une phase d'assemblage (pensez vos méthodes métier comme ayant un contrat strict avec la couche de présentation à propos de quelles données sont disponibles dans les objets détachés) à moins que vous soyez préparés à garder le contexte de persistance (la session) ouvert à travers tout le processus de rendu de la vue.

Pensez à abstraite votre logique métier d'Hibernate.

Cachez le mécanisme d'accès aux données (Hibernate) derrière une interface. Combinez les patterns DAO et Thread Local Session. Vous pouvez même avoir quelques classes persistées par du JDBC pur, associées à Hibernate via un UserType (ce conseil est valable pour des applications de taille respectables ; il n'est pas valable pour une application avec cinq tables).

N'utilisez pas d'associations de mapping exotiques.

De bons cas d'utilisation pour de vraies associations plusieurs-vers-plusieurs sont rares. La plupart du temps vous avez besoin d'informations additionnelles stockées dans la table d'association. Dans ce cas, il est préférable d'utiliser deux associations un-vers-plusieurs vers une classe de liaisons intermédiaire. En fait, nous pensons que la plupart des associations sont de type un-vers-plusieurs ou plusieurs-vers-un, vous devez être très attentifs lorsque vous utilisez autre chose et vous demander si c'est vraiment nécessaire.

Préférez les associations bidirectionnelles.

Les associations unidirectionnelles sont plus difficiles à questionner. Dans une grande application, la plupart des associations devraient être navigables dans les deux directions dans les requêtes.