Chapitre 3. Configuration

Parce qu'Hibernate est conçu pour fonctionner dans différents environnements, il existe beaucoup de paramètres de configuration. Heureusement, la plupart ont des valeurs par défaut appropriées et la distribution d'Hibernate contient un exemple de fichier hibernate.properties dans le répertoire etc/ qui montre les différentes options. Vous n'avez qu'à placer ce fichier dans votre classpath et à l'adapter.

3.1. Configuration par programmation

Une instance de org.hibernate.cfg.Configuration représente un ensemble de mappings des classes Java d'une application vers la base de données SQL. La Configuration est utilisée pour construire un objet (immuable) SessionFactory. Les mappings sont constitués d'un ensemble de fichiers de mapping XML.

Vous pouvez obtenir une instance de Configuration en l'instanciant directement et en spécifiant la liste des documents XML de mapping. Si les fichiers de mapping sont dans le classpath, vous pouvez le faire à l'aide de la méthode addResource() :

Configuration cfg = new Configuration()
    .addResource("Item.hbm.xml")
    .addResource("Bid.hbm.xml");

Une alternative (parfois meilleure) est de spécifier les classes mappées et de laisser Hibernate trouver les documents de mapping pour vous :

Configuration cfg = new Configuration()
    .addClass(org.hibernate.auction.Item.class)
    .addClass(org.hibernate.auction.Bid.class);

Hibernate va rechercher les fichiers de mappings /org/hibernate/auction/Item.hbm.xml et /org/hibernate/auction/Bid.hbm.xml dans le classpath. Cette approche élimine les noms de fichiers en dur.

Une Configuration vous permet également de préciser des propriétés de configuration :

Configuration cfg = new Configuration()
    .addClass(org.hibernate.auction.Item.class)
    .addClass(org.hibernate.auction.Bid.class)
    .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
    .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test")
    .setProperty("hibernate.order_updates", "true");

Ce n'est pas le seul moyen de passer des propriétés de configuration à Hibernate. Les différentes options sont :

  1. Passer une instance de java.util.Properties à Configuration.setProperties().

  2. Placer hibernate.properties dans un répertoire racine du classpath

  3. Positionner les propriétés System en utilisant java -Dproperty=value.

  4. Inclure des éléments <property> dans le fichier hibernate.cfg.xml (voir plus loin).

L'utilisation d'hibernate.properties est l'approche la plus simple si vous voulez démarrer rapidement

La Configuration est un objet de démarrage qui sera supprimé une fois qu'une SessionFactory aura été créée.

3.2. Obtenir une SessionFactory

Une fois que tous les mappings ont été parsés par la Configuration, l'application doit obtenir une fabrique d'instances de Session. Cette fabrique sera partagée entre tous les threads de l'application :

SessionFactory sessions = cfg.buildSessionFactory();

Hibernate permet à votre application d'instancier plus d'une SessionFactory. Cela est pratique lorsque vous utilisez plus d'une base de données.

3.3. Connexions JDBC

Habituellement, vous voulez que la SessionFactory crée les connexions JDBC et les mette dans un pool pour vous. Si vous suivez cette approche, ouvrir une Session est aussi simple que :

Session session = sessions.openSession(); // open a new Session

Dès que vous ferez quelquechose qui requiert un accès à la base de données, une connexion JDBC sera récupérée dans le pool.

Pour faire cela, il faut passer les propriétés de la connexion JDBC à Hibernate. Tous les noms des propriétés Hibernate et leur signification sont définies dans la classe org.hibernate.cfg.Environment. Nous allons maintenant décrire les paramètres de configuration des connexions JDBC les plus importants.

Hibernate obtiendra des connexions (et les mettra dans un pool) en utilisant java.sql.DriverManager si vous positionnez les paramètres de la manière suivante :

Tableau 3.1. Propriétés JDBC d'Hibernate

Nom de la propriétéFonction
hibernate.connection.driver_classClasse du driver jdbc
hibernate.connection.urlURL jdbc
hibernate.connection.usernameutilisateur de la base de données
hibernate.connection.passwordmot de passe de la base de données
hibernate.connection.pool_sizenombre maximum de connexions dans le pool

L'algorithme natif de pool de connexions d'Hibernate est plutôt rudimentaire. Il a été fait dans le but de vous aider à démarrer et n'est pas prévu pour un système en production ou même pour un test de peformance. Utilisez plutôt un pool tiers pour de meilleures performances et une meilleure stabilité : pour cela, remplacez la propriété hibernate.connection.pool_size avec les propriétés spécifique au pool de connexions que vous avez choisi. Cela désactivera le pool de connexions interne d'Hibernate. Vous pouvez par exemple utiliser C3P0.

C3P0 est un pool de connexions JDBC open source distribué avec Hibernate dans le répertoire lib. Hibernate utilisera son provider C3P0ConnectionProvider pour le pool de connexions si vous positionnez les propriétés hibernate.c3p0.*. Si vous voulez utiliser Proxool, référez vous au groupe de propriétés d'hibernate.properties correspondant et regardez sur le site web d'Hibernate pour plus d'informations.

Voici un exemple de fichier hibernate.properties pour C3P0:

hibernate.connection.driver_class = org.postgresql.Driver
hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
hibernate.connection.username = myuser
hibernate.connection.password = secret
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.timeout=1800
hibernate.c3p0.max_statement=50
hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

Dans le cadre de l'utilisation au sein d'un serveur d'applications, vous devriez quasiment toujours configurer Hibernate pour qu'il obtienne ses connexions de la DataSource du serveur d'application enregistrée dans le JNDI. Pour cela vous devrez définir au moins une des propriétés suivantes :

Tableau 3.2. Propriété d'une Datasource Hibernate

Nom d'une propriétéfonction
hibernate.connection.datasourceNom JNDI de la datasource
hibernate.jndi.urlURL du fournisseur JNDI (optionnelle)
hibernate.jndi.classClasse de l'InitialContextFactory du JNDI (optionnelle)
hibernate.connection.usernameutilisateur de la base de données (optionnelle)
hibernate.connection.passwordmot de passe de la base de données (optionnelle)

Voici un exemple de fichier hibernate.properties pour l'utilisation d'une datasource JNDI fournie par un serveur d'applications :

hibernate.connection.datasource = java:/comp/env/jdbc/test
hibernate.transaction.factory_class = \
    org.hibernate.transaction.JTATransactionFactory
hibernate.transaction.manager_lookup_class = \
    org.hibernate.transaction.JBossTransactionManagerLookup
hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

Les connexions JDBC obtenues à partir d'une datasource JNDI participeront automatiquement aux transactions gérées par le conteneur du serveur d'applications.

Des propriétés supplémentaires de connexion peuvent être passées en préfixant le nom de la propriété par "hibernate.connnection". Par exemple, vous pouvez spécifier un jeu de caractères en utilisant hibernate.connection.charSet.

Vous pouvez fournir votre propre stratégie d'obtention des connexions JDBC en implémentant l'interface org.hibernate.connection.ConnectionProvider. Vous pouvez sélectionner une implémentation spécifique en positionnant hibernate.connection.provider_class.

3.4. Propriétés de configuration optionnelles

Il y a un certain nombre d'autres propriétés qui contrôlent le fonctionnement d'Hibernate à l'exécution. Toutes sont optionnelles et ont comme valeurs par défaut des valeurs "raisonnables" pour un fonctionnement nominal.

Attention : Certaines de ces propriétés sont uniquement de niveau System. Les propriétés de niveau System ne peuvent être positionnées que via la ligne de commande (java -Dproperty=value) ou être définies dans hibernate.properties. Elle ne peuvent pas l'être via une des autres techniques décrites ci-dessus.

Tableau 3.3. Propriétés de configuration d'Hibernate

Nom de la propriétéFonction
hibernate.dialect Le nom de la classe du Dialect Hibernate. qui permet à Hibernate de générer du SQL optimisé pour une base de données relationnelle particulière.

ex. nom.complet.de.ma.classe.de.Dialect

hibernate.show_sql Ecrit toutes les requêtes SQL sur la console. Il s'agit d'une alternative au positionnement de la catégorie de log org.hibernate.SQL au niveau debug.

ex. true | false

hibernate.format_sql Formate et indente le sql dans la console et dans le log

ex. true | false

hibernate.default_schema Positionne dans le SQL généré un schéma/tablespace par défaut pour les noms de table ne l'ayant pas surchargé.

ex. MON_SCHEMA

hibernate.default_catalog Qualifie les noms de tables non qualifiées avec ce catalogue dans le SQL généré.

ex. CATALOG_NAME

hibernate.session_factory_name La SessionFactory sera automatiquement liée à ce nom dans le JNDI après sa création.

ex. jndi/nom/hierarchique

hibernate.max_fetch_depth Définit la profondeur maximale d'un arbre de chargement par jointures ouvertes pour les associations à cardinalité unitaire (un-à-un, plusieurs-à-un). Un 0 désactive le chargement par jointure ouverte.

ex. valeurs recommandées entre 0 et 3

hibernate.default_batch_fetch_size Définit une taille par défaut pour le chargement par lot des associations

ex. Valeurs recommandées : 4, 8, 16

hibernate.default_entity_mode Définit un mode de représentation par défaut des entités pour toutes les sessions ouvertes depuis cette SessionFactory

dynamic-map, dom4j, pojo

hibernate.order_updates Force Hibernate à trier les updates SQL par la valeur de la clé primaire des éléments qui sont mis à jour. Cela permet de limiter les deadlocks de transaction dans les systèmes hautement concurents.

ex. true | false

hibernate.generate_statistics Si activé, Hibernate va collecter des statistiques utiles pour le réglage des performances.

ex. true | false

hibernate.use_identifer_rollback Si activé, les propriétés correspondant à l'identifiant des objets vont être remises aux valeurs par défaut lorsque les objets seront supprimés.

ex. true | false

hibernate.use_sql_comments Si activé, Hibernate va générer des commentaires à l'intérieur des requêtes SQL pour faciliter le debogage., par défaut à false.

ex. true | false

Tableau 3.4. Propriétés Hibernate liées à JDBC et aux connexions

Nom de la propriétéFonction
hibernate.jdbc.fetch_size Une valeur non nulle détermine la taille de chargement des statements JDBC (appelle Statement.setFetchSize()).
hibernate.jdbc.batch_size Une valeur non nulle active l'utilisation par Hibernate des mises à jour par batch de JDBC2.

ex. les valeurs recommandées entre 5 et 30

hibernate.jdbc.batch_versioned_data Paramétrez cette propriété à true si votre pilote JDBC retourne des row counts corrects depuis executeBatch() (il est souvent approprié d'activer cette option). Hibernate utilisera alors le "batched DML" pour versionner automatiquement les données. Par défaut = false.

eg. true | false

hibernate.jdbc.factory_class Sélectionne un Batcher personnalisé. La plupart des applications n'auront pas besoin de cette propriété de configuration

ex. classname.of.Batcher

hibernate.jdbc.use_scrollable_resultset Active l'utilisation par Hibernate des resultsets scrollables de JDBC2. Cette propriété est seulement nécessaire lorsque l'on utilise une connexion JDBC fournie par l'utilisateur. Autrement, Hibernate utilise les métadonnées de la connexion.

ex. true | false

hibernate.jdbc.use_streams_for_binary Utilise des flux lorsque l'on écrit/lit des types binary ou serializable vers et à partir de JDBC (propriété de niveau système).

ex. true | false

hibernate.jdbc.use_get_generated_keys Active l'utilisation de PreparedStatement.getGeneratedKeys() de JDBC3 pour récupérer nativement les clés générées après insertion. Nécessite un pilote JDBC3+, le mettre à false si votre pilote a des problèmes avec les générateurs d'identifiant Hibernate. Par défaut, essaie de déterminer les possibilités du pilote en utilisant les meta données de connexion.

eg. true|false

hibernate.connection.provider_class Le nom de la classe d'un ConnectionProvider personnalisé qui fournit des connexions JDBC à Hibernate

ex. classname.of.ConnectionProvider

hibernate.connection.isolation Définit le niveau d'isolation des transactions JDBC. Regardez java.sql.Connection pour connaître le sens des différentes valeurs mais notez également que la plupart des bases de données ne supportent pas tous les niveaux d'isolation.

ex. 1, 2, 4, 8

hibernate.connection.autocommit Active le mode de commit automatique (autocommit) pour les connexions JDBC du pool (non recommandé).

ex. true | false

hibernate.connection.release_mode Spécifie à quel moment Hibernate doit relacher les connexion JDBC. Par défaut une connexion JDBC est conservée jusqu'à ce que la session soit explicitement fermée ou déconnectée. Pour une source de données JTA d'un serveur d'application, vous devriez utiliser after_statement pour libérer les connexions de manière plus agressive après chaque appel JDBC. Pour une connexion non JTA, il est souvent préférable de libérer la connexion à la fin de chaque transaction en utilisant after_transaction. auto choisira after_statement pour des transactions JTA et CMT et after_transaction pour des transactions JDBC.

ex. on_close (default) | after_transaction | after_statement | auto

hibernate.connection.<propertyName> Passe la propriété JDBCpropertyName à DriverManager.getConnection().
hibernate.jndi.<propertyName> Passe la propriété propertyName à l'InitialContextFactory de JNDI.

Tableau 3.5. Propriétés du Cache d'Hibernate

Nom de la propriétéFonction
hibernate.cache.provider_class Le nom de classe d'un CacheProvider spécifique.

ex. nom.de.classe.du.CacheProvider

hibernate.cache.use_minimal_puts Optimise le cache de second niveau en minimisant les écritures, au prix de plus de lectures. Ce paramètre est surtout utile pour les caches en cluster et est activé par défaut dans hibernate3 pour les implémentations de cache en cluster.

ex. true|false

hibernate.cache.use_query_cache Activer le cache de requête, les requêtes individuelles doivent tout de même être déclarées comme pouvant être mise en cache.

ex. true|false

hibernate.cache.use_second_level_cache Peut être utilisé pour désactiver complètement le cache de second niveau qui est activé par défaut pour les classes qui spécifient un élément <cache> dans leur mapping.

ex. true|false

hibernate.cache.query_cache_factory Le nom de classe d'une interface QueryCacheFactory , par défaut = built-in StandardQueryCacheFactory.

ex. nom.de.la.classe.de.QueryCacheFactory

hibernate.cache.region_prefix Un préfixe à utiliser pour le nom des régions du cache de second niveau.

ex. prefix

hibernate.cache.use_structured_entries Force Hibernate à stocker les données dans le cache de second niveau dans un format plus adapté à la visualisation par un humain.

ex. true|false

Tableau 3.6. Propriétés des transactions Hibernate

Nom de la propriétéFonction
hibernate.transaction.factory_class Le nom de classe d'une TransactionFactory qui sera utilisée par l'API Transaction d'Hibernate (la valeur par défaut est JDBCTransactionFactory).

ex. nom.de.classe.d.une.TransactionFactory

jta.UserTransaction Le nom JNDI utilisé par la JTATransactionFactory pour obtenir la UserTransaction JTA du serveur d'applications.

eg. jndi/nom/compose

hibernate.transaction.manager_lookup_class Le nom de la classe du TransactionManagerLookup - requis lorsque le cache de niveau JVM est activé ou lorsque l'on utilise un générateur hilo dans un environnement JTA.

ex. nom.de.classe.du.TransactionManagerLookup

hibernate.transaction.flush_before_completion Si activé, la session sera automatiquement vidée durant la phase qui précède la fin de la transaction (before completion). La gestion automatique de contexte fourni par Hibernate est recommandée, voir Section 2.5, « Sessions Contextuelles ».

ex. true | false

hibernate.transaction.auto_close_session Si activé, la session sera automatiquement fermé pendant la phase qui suit la fin de la transaction (after completion). La gestion automatique de contexte fourni par Hibernate est recommandée, voir

ex. true | false

Tableau 3.7. Propriétés diverses

Nom de la propriétéFonction
hibernate.current_session_context_class Fournit une stratégie particulière pour contextualiser la Session courante. Voir Section 2.5, « Sessions Contextuelles » pour plus d'informations sur les stratégies fournies.

eg. jta | thread | managed | custom.Class

hibernate.query.factory_class Choisi l'implémentation du parseur de requête

ex. org.hibernate.hql.ast.ASTQueryTranslatorFactory ou org.hibernate.hql.classic.ClassicQueryTranslatorFactory

hibernate.query.substitutions Lien entre les tokens de requêtes Hibernate et les tokens SQL (les tokens peuvent être des fonctions ou des noms littéraux par exemple).

ex. hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC

hibernate.hbm2ddl.auto Valide ou exporte automatiquement le schéma DDL vers la base de données lorsque la SessionFactory est créée. La valeur create-drop permet de supprimer le schéma de base de données lorsque la SessionFactory est fermée explicitement.

ex. validate | update | create | create-drop

hibernate.cglib.use_reflection_optimizer Active l'utilisation de CGLIB à la place de la réflexion à l'exécution (Propriété de niveau système). La réflexion peut parfois être utile pour résoudre des problèmes. Notez qu'Hibernate a tout de même toujours besoin de CGLIB même si l'optimiseur est désactivé. Cette optimisation ne peut être définie que dans le fichier hibernate.cfg.xml.

ex. true | false

3.4.1. Dialectes SQL

Vous devriez toujours positionner la propriété hibernate.dialect à la sous-classe de org.hibernate.dialect.Dialect appropriée à votre base de données. Si vous spécifiez un dialecte, Hibernate utilisera des valeurs adaptées pour certaines autres propriétés listées ci-dessus, vous évitant l'effort de le faire à la main.

Tableau 3.8. Dialectes SQL d'Hibernate (hibernate.dialect)

SGBDDialecte
DB2org.hibernate.dialect.DB2Dialect
DB2 AS/400org.hibernate.dialect.DB2400Dialect
DB2 OS390org.hibernate.dialect.DB2390Dialect
PostgreSQLorg.hibernate.dialect.PostgreSQLDialect
MySQLorg.hibernate.dialect.MySQLDialect
MySQL with InnoDBorg.hibernate.dialect.MySQLInnoDBDialect
MySQL with MyISAMorg.hibernate.dialect.MySQLMyISAMDialect
Oracle (any version)org.hibernate.dialect.OracleDialect
Oracle 9i/10gorg.hibernate.dialect.Oracle9Dialect
Sybaseorg.hibernate.dialect.SybaseDialect
Sybase Anywhereorg.hibernate.dialect.SybaseAnywhereDialect
Microsoft SQL Serverorg.hibernate.dialect.SQLServerDialect
SAP DBorg.hibernate.dialect.SAPDBDialect
Informixorg.hibernate.dialect.InformixDialect
HypersonicSQLorg.hibernate.dialect.HSQLDialect
Ingresorg.hibernate.dialect.IngresDialect
Progressorg.hibernate.dialect.ProgressDialect
Mckoi SQLorg.hibernate.dialect.MckoiDialect
Interbaseorg.hibernate.dialect.InterbaseDialect
Pointbaseorg.hibernate.dialect.PointbaseDialect
FrontBaseorg.hibernate.dialect.FrontbaseDialect
Firebirdorg.hibernate.dialect.FirebirdDialect

3.4.2. Chargement par Jointure Ouverte

Si votre base de données supporte les outer joins de type ANSI, Oracle ou Sybase, le chargement par jointure ouverte devrait améliorer les performances en limitant le nombre d'aller-retour avec la base de données (la base de données effectuant donc potentiellement plus de travail). Le chargement par jointure ouverte permet à un graphe entier d'objets connectés par une relation plusieurs-à-un, un-à-plusieurs ou un-à-un d'être chargé en un seul SELECT SQL.

Le chargement par jointure ouverte peut être désactiver globalement en mettant la propriété hibernate.max_fetch_depth à 0. Une valeur de 1 ou plus active le chargement par jointure ouverte pour les associatiosn un-à-un et plusieurs-à-un qui ont été mappée avec fetch="join".

Reportez vous à Section 19.1, « Stratégies de chargement » pour plus d'information.

3.4.3. Flux binaires

Oracle limite la taille d'un tableau de byte qui peuvent être passées à et vers son pilote JDBC. Si vous souhaitez utiliser des instances larges de type binary ou serializable, vous devez activer la propriété hibernate.jdbc.use_streams_for_binary. C'est une fonctionalité de niveau système uniquement.

3.4.4. Cache de second niveau et cache de requêtes

Les propriétés préfixées par hibernate.cache vous permettent d'utiliser un système de cache de second niveau. Ce cache peut avoir une portée dans le processus ou même être utilisable dans un système distribué. Référez vous au chapitre Section 19.2, « Le cache de second niveau » pour plus de détails.

3.4.5. Substitution dans le langage de requêtage

Vous pouvez définir de nouveaux tokens dans les requêtes Hibernate en utilisant la propriété hibernate.query.substitutions. Par exemple :

hibernate.query.substitutions vrai=1, faux=0

remplacerait les tokens vrai et faux par des entiers dans le SQL généré.

hibernate.query.substitutions toLowercase=LOWER

permettrait de renommer la fonction SQL LOWER en toLowercase

3.4.6. Statistiques Hibernate

Si vous activez hibernate.generate_statistics, Hibernate va fournir un certains nombre de métriques utiles pour régler les performances d'une application qui tourne via SessionFactory.getStatistics(). Hibernate peut aussi être configuré pour exposer ces statistiques via JMX. Lisez les Javadoc des interfaces dans le package org.hibernate.stats pour plus d'informations.

3.5. Tracer

Hibernate trace divers évènements en utilisant Apache commons-logging.

Le service commons-logging délèguera directement à Apache Log4j (si vous incluez log4j.jar dans votre classpath) ou le système de trace du JDK 1.4 (si vous tournez sous le JDK 1.4 et supérieur). Vous pouvez télécharger Log4j à partir de http://jakarta.apache.org. Pour utiliser Log4j, vous devrez placer dans votre classpath un fichier log4j.properties. Un exemple de fichier est distribué avec Hibernate dans le répertoire src/.

Nous vous recommandons fortement de vous familiariser avec les messages des traces d'Hibernate. Beaucoup de soins a été apporté pour donner le plus de détails possible sans les rendre illisibles. C'est un outil essentiel en cas de soucis. Les catégories de trace les plus intéressantes sont les suivantes :

Tableau 3.9. Catégories de trace d'Hibernate

CatégorieFonction
org.hibernate.SQLTrace toutes les requêts SQL de type DML (gestion des données) qui sont exécutées
org.hibernate.typeTrace tous les paramètres JDBC
org.hibernate.tool.hbm2ddlTrace toutes les requêts SQL de type DDL (gestion de la structure de la base) qui sont exécutées
org.hibernate.pretty Trace l'état de toutes les entités (20 entités maximum) qui sont associées avec la session hibernate au moment du flush
org.hibernate.cacheTrace toute l'activité du cache de second niveau
org.hibernate.transactionTrace toute l'activité relative aux transactions
org.hibernate.jdbcTrace toute acquisition de ressource JDBC
org.hibernate.hql.ast.AST Trace l'arbre syntaxique des requêtes HQL et SQL durant l'analyse syntaxique des requêtes
org.hibernate.secureTrace toutes les demandes d'autorisation JAAS
org.hibernate Trace tout (beaucoupe d'informations, mais très utile pour résoudre les problèmes).

Lorsque vous développez des applications avec Hibernate, vous devriez quasiment toujours travailler avec le niveau debug activé pour la catégorie org.hibernate.SQL, ou sinon avec la propriété hibernate.show_sql activée.

3.6. Implémenter une NamingStrategy

L'interface org.hibernate.cfg.NamingStrategy vous permet de spécifier une "stratégie de nommage" des objets et éléments de la base de données.

Vous pouvez fournir des règles pour automatiquement générer les identifiants de base de données à partir des identifiants Java, ou transformer une colonne ou table "logique" donnée dans le fichier de mapping en une colonne ou table "physique". Cette fonctionnalité aide à réduire la verbosité de documents de mapping, en éliminant le bruit répétitif (les préfixes TBL_ par exemple). La stratégie par défaut utilisée par Hibernate est minimale.

Vous pouvez définir une stratégie différente en appelant Configuration.setNamingStrategy() avant d'ajouter des mappings :

SessionFactory sf = new Configuration()
    .setNamingStrategy(ImprovedNamingStrategy.INSTANCE)
    .addFile("Item.hbm.xml")
    .addFile("Bid.hbm.xml")
    .buildSessionFactory();

net.sf.hibernate.cfg.ImprovedNamingStrategy est une stratégie fournie qui peut être utile comme point de départ de quelques applications.

3.7. Fichier de configuration XML

Une approche alternative est de spécifier toute la configuration dans un fichier nommé hibernate.cfg.xml. Ce fichier peut être utilisé à la place du fichier hibernate.properties, voire même peut servir à surcharger les propriétés si les deux fichiers sont présents.

Le fichier de configuration XML doit par défaut se placer à la racine du CLASSPATH. En voici un exemple :

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <!-- a SessionFactory instance listed as /jndi/name -->
    <session-factory
        name="java:hibernate/SessionFactory">

        <!-- properties -->
        <property name="connection.datasource">java:/comp/env/jdbc/MyDB</property>
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="show_sql">false</property>
        <property name="transaction.factory_class">
            org.hibernate.transaction.JTATransactionFactory
        </property>
        <property name="jta.UserTransaction">java:comp/UserTransaction</property>

        <!-- mapping files -->
        <mapping resource="org/hibernate/auction/Item.hbm.xml"/>
        <mapping resource="org/hibernate/auction/Bid.hbm.xml"/>

        <!-- cache settings -->
        <class-cache class="org.hibernate.auction.Item" usage="read-write"/>
        <class-cache class="org.hibernate.auction.Bid" usage="read-only"/>
        <collection-cache collection="org.hibernate.auction.Item.bids" usage="read-write"/>

    </session-factory>

</hibernate-configuration>

Commme vous pouvez le voir, l'avantage de cette approche est l'externalisation des noms des fichiers de mapping de la configuration. Le fichier hibernate.cfg.xml est également plus pratique quand on commence à régler le cache d'Hibernate. Notez que vous pouvez choisir entre utiliser hibernate.properties ou hibernate.cfg.xml, les deux sont équivalents, sauf en ce qui concerne les bénéfices de l'utilisation de la syntaxe XML mentionnés ci-dessus.

Avec la configuration XML, démarrer Hibernate devient donc aussi simple que ceci :

SessionFactory sf = new Configuration().configure().buildSessionFactory();

3.8. Intégration à un serveur d'application J2EE

Hibernate possède les points suivants d'intégration à l'infrastructure J2EE :

  • Source de données gérée par le conteneur : Hibernate peut utiliser des connexions JDBC gérées par le conteneur et fournie par l'intermédiaire de JNDI. Souvent, un TransactionManager compatible JTA et un ResourceManager s'occupent de la gestion des transactions (CMT). Ils sont particulièrement prévus pour pouvoir gérer des transactions distribuées sur plusieurs sources de données. Vous pouvez bien sûr également définir vos limites de transaction dans votre programme (BMT) ou vous pouvez sinon aussi utiliser l'API optionnelle Transaction d'Hibernate qui vous garantira la portabilité de votre code entre plusieurs serveurs d'application.

  • Association JNDI automatique: Hibernate peut associer sa SessionFactory à JNDI après le démarrage.

  • Association de la Session à JTA: La Session Hibernate peut être associée automatiquement à une transaction JTA si vous utilisez les EJBs. Vous avez juste à récupérer la SessionFactory depuis JNDI et à récupérer la Session courante. Hibernate s'occupe de vider et fermer la Session lorsque le transaction JTA se termine. La démarcation des transactions se fait de manière déclarative dans les descripteurs de déploiement.

  • Déploiement JMX :Si vous avez un serveur d'application compatible JMX (JBoss AS par exemple), vous pouvez choisir de déployer Hibernate en temps que MBean géré par le serveur. Cela vous évite de coder la ligne de démarrage qui permet de construire la SessionFactory depuis la Configuration. Le conteneur va démarrer votre HibernateService, et va idéalement s'occuper des dépendances entre les services (la source de données doit être disponible avant qu'Hibernate ne démarre, etc).

En fonction de votre environnement, vous devrez peut être mettre l'option de configuration hibernate.connection.aggressive_release à vrai si le serveur d'application affiche des exceptions de type "connection containment".

3.8.1. Configuration de la stratégie transactionnelle

L'API de la Session Hibernate est indépendante de tout système de démarcation des transactions qui peut être présent dans votre architecture. Si vous laissez Hibernate utiliser l'API JDBC directement via un pool de connexion, vous devrez commencer et terminer vos transactions en utilisant l'API JDBC. Si votre application tourne à l'intérieur d'un serveur d'application J2EE, vous voudrez peut être utiliser les transactions gérées par les beans (BMT) et appeller l'API JTA et UserTransaction lorsque cela est nécessaire.

Pour conserver votre code portable entre ces deux environnements (et d'autres éventuels) nous vous recommandons d'utiliser l'API optionnelle Transaction d'Hibernate, qui va encapsuler et masquer le système de transaction sous-jacent. Pour cela, vous devez préciser une classe de fabrique d'instances de Transaction en positionnant la propriété hibernate.transaction.factory_class.

Il existe trois choix standards (fournis) :

net.sf.hibernate.transaction.JDBCTransactionFactory

délègue aux transactions de la base de données (JDBC). Valeur par défaut.

org.hibernate.transaction.JTATransactionFactory

délègue à CMT si une transaction existante est sous ce contexte (ex: méthode d'un EJB session), sinon une nouvelle transaction est entamée et une transaction gérée par le bean est utilisée.

org.hibernate.transaction.CMTTransactionFactory

délègue à aux transactions JTA gérées par le conteneur

Vous pouvez également définir votre propre stratégie transactionnelle (pour un service de transaction CORBA par exemple).

Certaines fonctionnalités d'Hibernate (i.e. le cache de second niveau, l'association automatique des Session à JTA, etc.) nécessitent l'accès au TransactionManager JTA dans un environnement "managé". Dans un serveur d'application, vous devez indiquer comment Hibernate peut obtenir une référence vers le TransactionManager, car J2EE ne fournit pas un seul mécanisme standard.

Tableau 3.10. TransactionManagers JTA

Fabrique de TransactionServeur d'application
org.hibernate.transaction.JBossTransactionManagerLookupJBoss
org.hibernate.transaction.WeblogicTransactionManagerLookupWeblogic
org.hibernate.transaction.WebSphereTransactionManagerLookupWebSphere
org.hibernate.transaction.WebSphereExtendedJTATransactionLookupWebSphere 6
org.hibernate.transaction.OrionTransactionManagerLookupOrion
org.hibernate.transaction.ResinTransactionManagerLookupResin
org.hibernate.transaction.JOTMTransactionManagerLookupJOTM
org.hibernate.transaction.JOnASTransactionManagerLookupJOnAS
org.hibernate.transaction.JRun4TransactionManagerLookupJRun4
org.hibernate.transaction.BESTransactionManagerLookupBorland ES

3.8.2. SessionFactory associée au JNDI

Une SessionFactory Hibernate associée au JNDI peut simplifier l'accès à la fabrique et donc la création de nouvelles Sessions. Notez que cela n'est pas lié avec les Datasource associées au JNDI, elles utilisent juste le même registre.

Si vous désirez associer la SessionFactory à un nom JNDI, spécifiez un nom (ex. java:hibernate/SessionFactory) en utilisant la propriété hibernate.session_factory_name. Si cette propriété est omise, la SessionFactory ne sera pas associée au JNDI (c'est particulièrement pratique dans les environnements ayant une implémentation de JNDI en lecture seule, comme c'est le cas pour Tomcat).

Lorsqu'il associe la SessionFactory au JNDI, Hibernate utilisera les valeurs de hibernate.jndi.url, hibernate.jndi.class pour instancier un contexte d'initialisation. S'ils ne sont pas spécifiés, l'InitialContext par défaut sera utilisé.

Hibernate va automatiquement placer la SessionFactory dans JNDI après avoir appelé cfg.buildSessionFactory(). Cela signifie que vous devez avoir cet appel dans un code de démarrage (ou dans une classe utilitaire) dans votre application sauf si vous utilisez le déploiement JMX avec le service HibernateService présenté plus tard dans ce document.

Si vous utilisez SessionFactory JNDI, un EJB ou n'importe quelle autre classe peut obtenir la SessionFactory en utilisant un lookup JNDI.

Nous recommandons que vous liiez la SessionFactory à JNDI dans les environnements managés et que vous utilisiez un singleton static si ce n'est pas le cas. Pour isoler votre application de ces détails, nous vous recommandons aussi de masquer le code de lookup actuel pour une SessionFactory dans une classe helper, comme HibernateUtil.getSessionFactory(). Notez qu'une telle classe est aussi un moyen efficace de démarrer Hibernate—voir chapitre 1.

3.8.3. Association automatique de la Session à JTA

Le moyen le plus simple de gérer les Sessions et transactions est la gestion automatique de session "courante" offerte par Hibernate. Voir détail à Section 2.5, « Sessions Contextuelles ». En utilisant le contexte de session "jta" session context, s'il n'y a pas de Session associée à la transaction JTA courante, une session sera démarrée et associée à la transaction JTA courante la première fois que vous appelez sessionFactory.getCurrentSession(). Les Sessions obtenue via getCurrentSession() dans une contexte "jta" seront automatiquement flushées avant la validation de la transaction, fermées une fois la transaction complétée, et libéreront les connexions JDBC de manière aggressive après chaque statement. Ceci permet aux Sessions d'être gérées par le cycle de vie de la transaction JTA à la quelle est sont associées, laissant le code de l'utilisateur propre de ce type de gestion. Votre code peut soit utiliser JTA de manière programmatique via UserTransaction, ou (ce qui est recommandé pour la portabilité du code) utiliser l'API Transaction API pour marquer les limites. Si vous exécutez sous un conteneur EJB, la démarcation déclarative des transactions avec CMT est recommandée.

3.8.4. Déploiement JMX

La ligne cfg.buildSessionFactory() doit toujours être exécutée quelque part pour avoir une SessionFactory dans JNDI. Vous pouvez faire cela dans un bloc d'initialisation static (comme celui qui se trouve dans la classe HibernateUtil) ou vous pouvez déployer Hibernate en temps que service managé.

Hibernate est distribué avec org.hibernate.jmx.HibernateService pour le déploiement sur un serveur d'application avec le support de JMX comme JBoss AS. Le déploiement et la configuration sont spécifiques à chaque vendeur. Voici un fichier jboss-service.xml d'exemple pour JBoss 4.0.x:

<?xml version="1.0"?>
<server>

<mbean code="org.hibernate.jmx.HibernateService"
    name="jboss.jca:service=HibernateFactory,name=HibernateFactory">

    <!-- Required services -->
    <depends>jboss.jca:service=RARDeployer</depends>
    <depends>jboss.jca:service=LocalTxCM,name=HsqlDS</depends>

    <!-- Bind the Hibernate service to JNDI -->
    <attribute name="JndiName">java:/hibernate/SessionFactory</attribute>

    <!-- Datasource settings -->
    <attribute name="Datasource">java:HsqlDS</attribute>
    <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute>

    <!-- Transaction integration -->
    <attribute name="TransactionStrategy">
        org.hibernate.transaction.JTATransactionFactory</attribute>
    <attribute name="TransactionManagerLookupStrategy">
        org.hibernate.transaction.JBossTransactionManagerLookup</attribute>
    <attribute name="FlushBeforeCompletionEnabled">true</attribute>
    <attribute name="AutoCloseSessionEnabled">true</attribute>

    <!-- Fetching options -->
    <attribute name="MaximumFetchDepth">5</attribute>

    <!-- Second-level caching -->
    <attribute name="SecondLevelCacheEnabled">true</attribute>
    <attribute name="CacheProviderClass">org.hibernate.cache.EhCacheProvider</attribute>
    <attribute name="QueryCacheEnabled">true</attribute>

    <!-- Logging -->
    <attribute name="ShowSqlEnabled">true</attribute>

    <!-- Mapping files -->
    <attribute name="MapResources">auction/Item.hbm.xml,auction/Category.hbm.xml</attribute>

</mbean>

</server>

Ce fichier est déployé dans un répertoire META-INF et est packagé dans un fichier JAR avec l'extension .sar (service archive). Vous devez également packager Hibernate, les librairies tierces requises, vos classes persistantes compilées et vos fichiers de mapping dans la même archive. Vos beans entreprise (souvent des EJBs session) peuvent rester dans leur propre fichier JAR mais vous pouvez inclure ce fichier JAR dans le jar principal du service pour avoir une seule unité déployable à chaud. Vous pouvez consulter la documentation de JBoss AS pour plus d'information sur les services JMX et le déploiement des EJBs.