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.
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 :
Passer une instance de java.util.Properties à Configuration.setProperties().
Placer hibernate.properties dans un répertoire racine du classpath
Positionner les propriétés System en utilisant java -Dproperty=value.
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.
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.
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_class | Classe du driver jdbc |
hibernate.connection.url | URL jdbc |
hibernate.connection.username | utilisateur de la base de données |
hibernate.connection.password | mot de passe de la base de données |
hibernate.connection.pool_size | nombre 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.datasource | Nom JNDI de la datasource |
hibernate.jndi.url | URL du fournisseur JNDI (optionnelle) |
hibernate.jndi.class | Classe de l'InitialContextFactory du JNDI (optionnelle) |
hibernate.connection.username | utilisateur de la base de données (optionnelle) |
hibernate.connection.password | mot 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.
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 |
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)
SGBD | Dialecte |
---|---|
DB2 | org.hibernate.dialect.DB2Dialect |
DB2 AS/400 | org.hibernate.dialect.DB2400Dialect |
DB2 OS390 | org.hibernate.dialect.DB2390Dialect |
PostgreSQL | org.hibernate.dialect.PostgreSQLDialect |
MySQL | org.hibernate.dialect.MySQLDialect |
MySQL with InnoDB | org.hibernate.dialect.MySQLInnoDBDialect |
MySQL with MyISAM | org.hibernate.dialect.MySQLMyISAMDialect |
Oracle (any version) | org.hibernate.dialect.OracleDialect |
Oracle 9i/10g | org.hibernate.dialect.Oracle9Dialect |
Sybase | org.hibernate.dialect.SybaseDialect |
Sybase Anywhere | org.hibernate.dialect.SybaseAnywhereDialect |
Microsoft SQL Server | org.hibernate.dialect.SQLServerDialect |
SAP DB | org.hibernate.dialect.SAPDBDialect |
Informix | org.hibernate.dialect.InformixDialect |
HypersonicSQL | org.hibernate.dialect.HSQLDialect |
Ingres | org.hibernate.dialect.IngresDialect |
Progress | org.hibernate.dialect.ProgressDialect |
Mckoi SQL | org.hibernate.dialect.MckoiDialect |
Interbase | org.hibernate.dialect.InterbaseDialect |
Pointbase | org.hibernate.dialect.PointbaseDialect |
FrontBase | org.hibernate.dialect.FrontbaseDialect |
Firebird | org.hibernate.dialect.FirebirdDialect |
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.
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.
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.
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
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.
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égorie | Fonction |
---|---|
org.hibernate.SQL | Trace toutes les requêts SQL de type DML (gestion des données) qui sont exécutées |
org.hibernate.type | Trace tous les paramètres JDBC |
org.hibernate.tool.hbm2ddl | Trace 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.cache | Trace toute l'activité du cache de second niveau |
org.hibernate.transaction | Trace toute l'activité relative aux transactions |
org.hibernate.jdbc | Trace 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.secure | Trace 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.
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.
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();
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".
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) :
délègue aux transactions de la base de données (JDBC). Valeur par défaut.
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.
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 Transaction | Serveur d'application |
---|---|
org.hibernate.transaction.JBossTransactionManagerLookup | JBoss |
org.hibernate.transaction.WeblogicTransactionManagerLookup | Weblogic |
org.hibernate.transaction.WebSphereTransactionManagerLookup | WebSphere |
org.hibernate.transaction.WebSphereExtendedJTATransactionLookup | WebSphere 6 |
org.hibernate.transaction.OrionTransactionManagerLookup | Orion |
org.hibernate.transaction.ResinTransactionManagerLookup | Resin |
org.hibernate.transaction.JOTMTransactionManagerLookup | JOTM |
org.hibernate.transaction.JOnASTransactionManagerLookup | JOnAS |
org.hibernate.transaction.JRun4TransactionManagerLookup | JRun4 |
org.hibernate.transaction.BESTransactionManagerLookup | Borland ES |
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.
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.
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.