Hibernate.org Community Documentation

- Précédent
- Suivant

## Chapitre 1. Tutoriel

A l'intention des nouveaux utilisateurs, ce chapitre fournit une introduction étape par étape à Hibernate, en commençant par une application simple, avec une base de données en-mémoire. Le tutoriel est basé sur une tutoriel antérieur qui avait été développé par Michael Gloegl. Tout le code est contenu dans `tutorials/web` qui se trouve dans le répertoire source du projet.

## Important

Ce tutoriel assume que l'utilisateur est déjà familier avec Java et SQL à la fois. Si vous ne possédez qu'une connaissance de Java et d'SQL limitée, il est conseillé de commencer par vous familiariser avec ces technologies avant d'aborder Hibernate.

## Note

La distribution contient un autre exemple d'application qui se trouve dans le répertoire source du projet `tutorial/eg`.

## 1.1. Section 1 - Première application Hibernate

Supposons que nous ayons besoin d'une petite application de base de données qui puisse stocker des événements que nous voulons suivre, et des informations à propos des hôtes de ces événements.

## Note

Malgré que vous puissiez utiliser tout base de données qui vous convienne, on choisira HSQLDB (une base de données Java, en-mémoire) pour éviter de décrire l'installation et la configuration de n'importe quel serveur de base de données particulière.

### 1.1.1. Configuration

La première chose que nous devons faire est de configurer l'environnement de développement. Nous utiliserons la "standard layout" préconisée par de nombreux outils de génération tels que Maven. Maven, en particulier, a une bonne ressource décrivant cette layout. Comme ce tutoriel va devenir une application web, nous allons créer et utiliser les répertoires `src/main/java.`, `src/main/ressources` et `src/main/webapp`.

Nous utiliserons Maven dans ce tutoriel. Nous profiterons de ses capacités de gestion de dépendances transitives, ainsi que de la capacité des nombreux IDE à installer automatiquement un projet sur la base du descripteur Maven.

    <project xmlns="http://maven.apache.org/POM/4.0.0"

             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

        <modelVersion>4.0.0</modelVersion>

        <groupId>org.hibernate.tutorials</groupId>

        <artifactId>hibernate-tutorial</artifactId>

        <version>1.0.0-SNAPSHOT</version>

        <name>First Hibernate Tutorial</name>

        <build>

             <!-- we dont want the version to be part of the generated war file name -->

             <finalName>${artifactId}</finalName>

        </build>

        <dependencies>

            <dependency>

                <groupId>org.hibernate</groupId>

                <artifactId>hibernate-core</artifactId>

            </dependency>

            <!-- Because this is a web app, we also have a dependency on the servlet api. -->

            <dependency>

                <groupId>javax.servlet</groupId>

                <artifactId>servlet-api</artifactId>

            </dependency>

            <!-- Hibernate uses slf4j for logging, for our purposes here use the simple backend -->

            <dependency>

                <groupId>org.slf4j</groupId>

                <artifactId>slf4j-simple</artifactId>

            </dependency>

            <!-- Hibernate gives you a choice of bytecode providers between cglib and javassist -->

            <dependency>

                <groupId>javassist</groupId>

                <artifactId>javassist</artifactId>

            </dependency>

        </dependencies>

    </project>

## Astuce

It is not a requirement to use Maven. If you wish to use something else to build this tutorial (such as Ant), the layout will remain the same. The only change is that you will need to manually account for all the needed dependencies. If you use something like Ivy providing transitive dependency management you would still use the dependencies mentioned below. Otherwise, you'd need to grab all dependencies, both explicit and transitive, and add them to the project's classpath. If working from the Hibernate distribution bundle, this would mean `hibernate3.jar`, all artifacts in the `lib/required` directory and all files from either the `lib/bytecode/cglib` or `lib/bytecode/javassist` directory; additionally you will need both the servlet-api jar and one of the slf4j logging backends.

Sauvegardez ce fichier sous la forme `pom.xml` dans le répertoire root du projet.

### 1.1.2. La première classe

Ensuite, nous créons une classe qui représente l'évènement que nous voulons stocker dans notre base de données. Il s'agit d'une simple classe JavaBean avec quelques propriétés :

    package org.hibernate.tutorial.domain;

    import java.util.Date;

    public class Event {

        private Long id;

        private String title;

        private Date date;

        public Event() {}

        public Long getId() {

            return id;

        }

        private void setId(Long id) {

            this.id = id;

        }

        public Date getDate() {

            return date;

        }

        public void setDate(Date date) {

            this.date = date;

        }

        public String getTitle() {

            return title;

        }

        public void setTitle(String title) {

            this.title = title;

        }

    }

Vous constaterez que cette classe utilise les conventions de nommage standard JavaBean pour les méthodes getter/setter des propriétés, ainsi qu'une visibilité privée pour les champs. Ceci est la conception recommandée - mais pas obligatoire. Hibernate peut aussi accéder aux champs directement, le bénéfice des méthodes d'accès est la robustesse pour la refonte de code.

La propriété `id` contient la valeur d'un identifiant unique pour un événement particulier. Toutes les classes d'entités persistantes (il y a également des classes dépendantes de moindre importance) auront besoin d'une telle propriété identifiante si nous voulons utiliser l'ensemble complet des fonctionnalités de Hibernate. En fait, la plupart des applications (surtout les applications web) ont besoin de distinguer des objets par des identifiants, par conséquent considérez cela comme une fonctionnalité et non comme une limitation. Cependant, nous ne manipulons généralement pas l'identité d'un objet, dorénavant la méthode setter devrait être privée. Seul Hibernate assignera les identifiants lorsqu'un objet est sauvegardé. Remarquez que Hibernate peut accéder aux méthodes publiques, privées et protégées, ainsi qu'aux champs (publics, privés, protégés) directement. À vous de choisir, et vous pouvez également l'ajuster à la conception de votre application.

Le constructeur sans argument est requis pour toutes les classes persistantes; Hibernate doit créer des objets pour vous en utilisant la réflexion Java. Le constructeur peut être privé, cependant, la visibilité du paquet est requise pour la génération de proxies à l'exécution et une récupération efficace des données sans instrumentation du bytecode.

Sauvegardez ce fichier dans le répertoire `src/main/java/org/hibernate/tutorial/domain`.

### 1.1.3. Le fichier de mappage

Hibernate a besoin de savoir comment charger et stocker des objets d'une classe persistante. C'est là qu'intervient le fichier de mappage Hibernate. Le fichier de mappage indique à Hibernate à quelle table accéder dans la base de données, et les colonnes de cette table à utiliser.

La structure basique de ce fichier de mappage ressemble à ce qui suit :

    <?xml version="1.0"?>

    <!DOCTYPE hibernate-mapping PUBLIC

            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

    <hibernate-mapping package="org.hibernate.tutorial.domain">

    [...]

    </hibernate-mapping

    >

Notez que la DTD Hibernate est très sophistiquée. Vous pouvez l'utiliser pour l'auto-finalisation des éléments et des attributs de mappage XML dans votre éditeur ou votre IDE. Ouvrez également le fichier DTD dans votre éditeur de texte - c'est le moyen le plus facile d'obtenir une vue d'ensemble de tous les éléments et attributs, et de voir les valeurs par défaut, ainsi que quelques commentaires. Notez qu'Hibernate ne chargera pas le fichier DTD à partir du web, mais regardera d'abord dans le chemin de classe de l'application. Le fichier DTD est inclus dans `hibernate-core.jar ainsi que` dans le répertoire `src` de la distribution Hibernate).

## Important

Nous omettrons la déclaration de la DTD dans les exemples futurs pour raccourcir le code. Évidemment il n'est pas optionnel.

Entre les deux balises `hibernate-mapping`, incluez un élément `class`. Toutes les classes d'entités persistantes (encore une fois, il pourrait y avoir des classes dépendantes plus tard, qui ne sont pas des entités mère) ont besoin d'un mappage vers une table de la base de données SQL :

    <hibernate-mapping package="org.hibernate.tutorial.domain">

        <class name="Event" table="EVENTS">

        </class>

    </hibernate-mapping>

Plus loin, nous indiquons à Hibernate comment persister et charger un objet de la classe `Event` dans la table `EVENTS`, chaque instance étant représentée par une ligne dans cette table. Maintenant nous continuons avec le mappage de la propriété de l'identifiant unique vers la clef primaire des tables. De plus, comme nous ne voulons pas nous occuper de la gestion de cet identifiant, nous utilisons une stratégie de génération d'identifiant Hibernate pour la colonne de la clé primaire subrogée :

    <hibernate-mapping package="org.hibernate.tutorial.domain">

        <class name="Event" table="EVENTS">

            <id name="id" column="EVENT_ID">

                <generator class="native"/>

            </id>

        </class>

    </hibernate-mapping>

L'élément `ID` est la déclaration de l'identifiant de propriété. L'attribut de mappage `name="id"` déclare le nom de la propriété JavaBean et indique à Hibernate d'utiliser les méthodes `getId()` et `setId()` pour accéder à la propriété. L'attribut de colonne indique à Hibernate quelle colonne de la table `EVENTS` contient la valeur de clé primaire.

L'élément imbriqué `Générateur` spécifie la stratégie de génération d'identifiant (c'est à dire comment les valeurs d'identifiant sont-elles générées?). Dans ce cas nous avons choisi `native`, qui offre un niveau de la portabilité selon le dialecte de base de données configurée. Mise en veille prolongée prend en charge la base de données générée, unique au monde, ainsi que l'application affectée, les identifiants. Génération de valeur d'identifiant est aussi l'un des nombreux points d'extension d'Hibernate et vous pouvez plug-in votre propre stratégie.

## Astuce

`native` is no longer consider the best strategy in terms of portability. for further discussion, see Section 28.4, « Générer les identifiants »

Enfin, nous incluons des déclarations pour les propriétés persistantes de la classe dans le fichier de mappage. Par défaut, aucune propriété de la classe n'est considérée comme persistante :

    <hibernate-mapping package="org.hibernate.tutorial.domain">

        <class name="Event" table="EVENTS">

            <id name="id" column="EVENT_ID">

                <generator class="native"/>

            </id>

            <property name="date" type="timestamp" column="EVENT_DATE"/>

            <property name="title"/>

        </class>

    </hibernate-mapping>

Comme avec l'élément `id`, l'attribut `name` de l'élément `property` indique à Hibernate quelles méthodes getters/setters utiliser. Par conséquent dans ce cas, Hibernate cherchera `getDate()/setDate()`, de même que `getTitle()/setTitle()`.

## Note

Pourquoi le mappage de la propriété `date` inclut-il l'attribut `column`, mais non le `title` ? Sans l'attribut `column`, Hibernate utilise par défaut le nom de la propriété comme nom de colonne. Cela fonctionne bien pour `title`. Cependant, `date` est un mot clé réservé dans la plupart des bases de données, donc nous utilisons un nom différent pour le mappage.

Il est intéressant de noter que le mappage de `title` manque également d'un attribut `type`. Les types que nous déclarons et utilisons dans les fichiers de mappage ne sont pas, comme vous pourriez vous y attendre, des types de données Java. Ce ne sont pas, non plus, des types de base de données SQL. Ces types sont donc appelés types de mappage Hibernate, des convertisseurs qui peuvent traduire des types Java en types SQL et vice versa. De plus, Hibernate tentera de déterminer la bonne conversion et le type de mappage lui-même si l'attribut `type` n'est pas présent dans le mappage. Dans certains cas, cette détection automatique (utilisant la réflexion sur la classe Java) pourrait ne pas donner la valeur attendue ou dont vous avez besoin. C'est le cas avec la propriété `date`. Hibernate ne peut pas savoir si la propriété "mappera" une colonne SQL de type `date`, `timestamp` ou `time`. Nous déclarons que nous voulons conserver des informations avec une date complète et l'heure en mappant la propriété avec un convertisseur `timestamp`.

## Astuce

Hibernate rend cette détermination de type de mappage en utilisant la réflection au moment du traitement des fichiers de mappage. Cela prend du temps et consomme des ressources, donc, si la performance de démarrage est importante, vous devriez considérer définir explicitement quel type utiliser.

Sauvegardez ce fichier de mappage ainsi `src/main/resources/org/hibernate/tutorial/domain/Event.hbm.xml`.

### 1.1.4. Configuration d'Hibernate

A ce niveau là, vous devriez avoir la classe persistante et son fichier de mappage en place. Il est temps maintenant de configurer Hibernate. Tout d'abord, il nous faut configurer HSQLDB pour qu'il puisse exécuter en "server mode"

## Note

We do this do that the data remains between runs.

Vous utiliserez le lugin exec Maven pour lancer le serveur HSQLDB en exécutant : `mvn exec:java -Dexec.mainClass="org.hsqldb.Server" -Dexec.args="-database.0 file:target/data/tutorial"`. Vous observez qu'elle démarre et ouvre un socket TCP/IP, c'est là que notre application se connectera plus tard. Si vous souhaitez démarrez à partir d'une nouvelle base de données pour ce tutoriel (choisissez `CTRL + C` dans la fenêtre), effacez tous les fichiers dans le répertoire `target/data` et redémarrez HSQL DB.

Hibernate se connectera à la base de données pour le compte de votre application, donc il devra savoir comment obtenir des connexions. Pour ce tutoriel, nous devrons utliser un pool de connexions autonomes (et non pas `javax.sql.DataSource`). Hibernate bénéficie du support de deux pools de connexions JDBC open source de tierce partie : c3p0 and proxool. Cependant, nous utiliserons le pool de connexions intégré Hibernate pour ce tutoriel.

## Attention

The built-in Hibernate connection pool is in no way intended for production use. It lacks several features found on any decent connection pool.

Pour la configuration de Hibernate, nous pouvons utiliser un simple fichier `hibernate.properties`, un fichier `hibernate.cfg.xml` légèrement plus sophistiqué, ou même une configuration complète par programmation. La plupart des utilisateurs préfèrent le fichier de configuration XML :

    <?xml version='1.0' encoding='utf-8'?>

    <!DOCTYPE hibernate-configuration PUBLIC

            "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

            "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

    <hibernate-configuration>

        <session-factory>

            <!-- Database connection settings -->

            <property name="connection.driver_class"

    >org.hsqldb.jdbcDriver</property>

            <property name="connection.url"

    >jdbc:hsqldb:hsql://localhost</property>

            <property name="connection.username"

    >sa</property>

            <property name="connection.password"

    ></property>

            <!-- JDBC connection pool (use the built-in) -->

            <property name="connection.pool_size"

    >1</property>

            <!-- SQL dialect -->

            <property name="dialect"

    >org.hibernate.dialect.HSQLDialect</property>

            <!-- Enable Hibernate's automatic session context management -->

            <property name="current_session_context_class"

    >thread</property>

            <!-- Disable the second-level cache  -->

            <property name="cache.provider_class"

    >org.hibernate.cache.NoCacheProvider</property>

            <!-- Echo all executed SQL to stdout -->

            <property name="show_sql"

    >true</property>

            <!-- Drop and re-create the database schema on startup -->

            <property name="hbm2ddl.auto"

    >update</property>

            <mapping resource="org/hibernate/tutorial/domain/Event.hbm.xml"/>

        </session-factory>

    </hibernate-configuration

    >

## Note

Vous pourrez remarquer que cette configuration XML utilise une DTD différente.

Nous configurons une `SessionFactory` de Hibernate - une fabrique globale responsable d'une base de données particulière. Si vous avez plusieurs base de données, utilisez plusieurs configurations `<session-factory>`, généralement dans des fichiers de configuration différents (pour un démarrage plus facile).

Les quatre premiers éléments `property` contiennent la configuration nécessaire pour la connexion JDBC. L'élément `property` du dialecte spécifie quelle variante du SQL Hibernate va générer.

## Astuce

In most cases, Hibernate is able to properly determine which dialect to use. See Section 28.3, « Résolution de dialecte » for more information.

La gestion automatique des sessions d'Hibernate pour les contextes de persistance est bien pratique, comme vous pourrez le constater. L'option `hbm2ddl.auto` active la génération automatique des schémas de base de données - directement dans la base de données. Cela peut également être désactivé (en supprimant l'option de configuration) ou redirigé vers un fichier avec l'aide de la tâche Ant `SchemaExport`. Finalement, nous ajoutons le(s) fichier(s) de mappage pour les classes persistantes.

Sauvegarder ce fichier en tant que `hibernate.cfg.xml` dans le répertoire `src/main/resources`.

### 1.1.5. Construction avec Maven

Nous allons maintenant construire le tutoriel avec Maven. Vous aurez besoin d'installer Maven pour cela. Il est disponible dans la page Maven download page. Maven pourra lire le fichier `/pom.xml` que nous avons créé plus tôt et saura comment effectuer quelques tâches du projet de base. Tout d'abord, exécutons `compile` pour s'assurer que nous pouvons tout compiler jusqu'à maintenant :

    [hibernateTutorial]$ mvn compile
    [INFO] Scanning for projects...
    [INFO] ------------------------------------------------------------------------
    [INFO] Building First Hibernate Tutorial
    [INFO]    task-segment: [compile]
    [INFO] ------------------------------------------------------------------------
    [INFO] [resources:resources]
    [INFO] Using default encoding to copy filtered resources.
    [INFO] [compiler:compile]
    [INFO] Compiling 1 source file to /home/steve/projects/sandbox/hibernateTutorial/target/classes
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESSFUL
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 2 seconds
    [INFO] Finished at: Tue Jun 09 12:25:25 CDT 2009
    [INFO] Final Memory: 5M/547M
    [INFO] ------------------------------------------------------------------------

### 1.1.6. Démarrage et aides

Il est temps de charger et de stocker quelques objets `Event`, mais d'abord nous devons compléter la configuration avec du code d'infrastructure. Nous devons démarrer Hibernate. Ce démarrage inclut la construction d'un objet `SessionFactory` global et le stocker dans un lieu facile d'accès dans le code de l'application. Une `SessionFactory` peut ouvrir de nouvelles `Session`s. Une `Session` représente une unité de travail simplement "threadée". La `org.hibernate.SessionFactory` est un objet global "thread-safe", instancié une seule fois.

Nous créerons une classe d'aide `HibernateUtil` qui s'occupe du démarrage et rend la gestion des `org.hibernate.SessionFactory` plus facile.

    package org.hibernate.tutorial.util;

    import org.hibernate.SessionFactory;

    import org.hibernate.cfg.Configuration;

    public class HibernateUtil {

        private static final SessionFactory sessionFactory = buildSessionFactory();

        private static SessionFactory buildSessionFactory() {

            try {

                // Create the SessionFactory from hibernate.cfg.xml

                return new Configuration().configure().buildSessionFactory();

            }

            catch (Throwable ex) {

                // Make sure you log the exception, as it might be swallowed

                System.err.println("Initial SessionFactory creation failed." + ex);

                throw new ExceptionInInitializerError(ex);

            }

        }

        public static SessionFactory getSessionFactory() {

            return sessionFactory;

        }

    }

Sauvegardez ce code en tant que `src/main/java/org/hibernate/tutorial/util/HibernateUtil.java`

Cette classe ne produit pas seulement la `org.hibernate.SessionFactory` globale dans un initialiseur statique. Elle masque le fait qu'elle exploite un singleton statique. Nous aurions pu aussi bien vérouiller la référence `org.hibernate.SessionFactory` à partir de JNDI dans un serveur d'application ou dans n'importe quelle location en fait. Elle pourrait aussi obtenir la `SessionFactory` depuis JNDI dans un serveur d'applications.

Si vous nommez `org.hibernate.SessionFactory` dans votre fichier de configuration, Hibernate tentera la récupération depuis JNDI. Pour éviter ce code, vous pouvez aussi utiliser un déploiement JMX et laisser le conteneur (compatible JMX) instancier et lier un `HibernateService` à JNDI. Ces options avancées sont expliquées plus loin.

Nous avons finalement besoin de configurer le système de journalisation - Hibernate utilise commons-logging et vous laisse le choix entre log4j et le système de logs du JDK 1.4. La plupart des développeurs préfèrent log4j : copiez `log4j.properties` de la distribution de Hibernate (il est dans le répertoire `etc/`) dans votre répertoire `src`, puis faîtes de même avec `hibernate.cfg.xml`. Regardez la configuration d'exemple et changez les paramètres si vous voulez une sortie plus verbeuse. Par défaut, seul le message de démarrage de Hibernate est affiché sur la sortie standard.

L'infrastructure de ce toturiel est complète - et nous sommes prêts à effectuer un travail réel avec Hibernate.

### 1.1.7. Charger et stocker des objets

We are now ready to start doing some real work with Hibernate. Let's start by writing an `EventManager` class with a `main()` method:

    package org.hibernate.tutorial;

    import org.hibernate.Session;

    import java.util.*;

    import org.hibernate.tutorial.domain.Event;

    import org.hibernate.tutorial.util.HibernateUtil;

    public class EventManager {

        public static void main(String[] args) {

            EventManager mgr = new EventManager();

            if (args[0].equals("store")) {

                mgr.createAndStoreEvent("My Event", new Date());

            }

            HibernateUtil.getSessionFactory().close();

        }

        private void createAndStoreEvent(String title, Date theDate) {

            Session session = HibernateUtil.getSessionFactory().getCurrentSession();

            session.beginTransaction();

            Event theEvent = new Event();

            theEvent.setTitle(title);

            theEvent.setDate(theDate);

            session.save(theEvent);

            session.getTransaction().commit();

        }

    }

Nous créons un nouvel objet `Event` dans `createAndStoreEvent()`, et nous le remettons à Hibernate, qui s'occupe maintenant du SQL et exécute les `INSERT` s dans la base de données.

A org.hibernate.Session is designed to represent a single unit of work (a single atomic piece of work to be performed). For now we will keep things simple and assume a one-to-one granularity between a Hibernate org.hibernate.Session and a database transaction. To shield our code from the actual underlying transaction system we use the Hibernate `org.hibernate.Transaction` API. In this particular case we are using JDBC-based transactional semantics, but it could also run with JTA.

Quelle est la fonction de `sessionFactory.getCurrentSession()` ? Premièrement, vous pouvez l'invoquer autant de fois que vous le voulez et n'importe où, du moment que vous avez votre `SessionFactory` (facile grâce à `HibernateUtil`). La méthode `getCurrentSession()` renvoie toujours l'unité de travail courante. Souvenez vous que nous avons basculé notre option de configuration au mécanisme basé sur le "thread" dans `hibernate.cfg.xml`. Par conséquent, l'unité de travail courante est liée au thread Java courant qui exécute notre application.

## Important

Hibernate offre trois méthodes le suivi de session courant. La méthode basée "thread" qui n'est pas conçue pour une utilisation de la production ; seulement utile pour les prototypes et des tutoriels comme celui-ci. Le suivi de session courant est abordé plus en détail par la suite.

Une org.hibernate.Session commence lorsque le thread courant commence à appeler `getCurrentSession()`. Ensuite, elle est attachée par Hibernate au thread courant. Lorsque la transaction s'achève, par commit ou par rollback, Hibernate détache automatiquement la `Session` du thread et la ferme pour vous. Si vous invoquez `getCurrentSession()` une nouvelle fois, vous obtenez une nouvelle `Session` et pouvez entamer une nouvelle unité de travail.

A propos de la portée de l'unité de travail, la session org.hibernate.Session Hibernate devrait-elle être utilisée pour exécuter une ou plusieurs opérations en base de données ? L'exemple ci-dessus utilise une `Session` pour une opération. C'est une pure coïncidence, l'exemple n'est pas assez complexe pour montrer d'autres approches. La portée d'une `Session` Hibernate est flexible mais vous ne devriez jamais concevoir votre application de manière à utiliser une nouvelle `Session` Hibernate pour chaque opération en base de données. Donc même si vous le voyez quelquefois dans les exemples suivants, considérez une session par opération comme un anti-modèle. Une véritable application (web) est affichée plus loin dans ce tutoriel.

See Chapitre 13, Transactions et Accès concurrents for more information about transaction handling and demarcation. The previous example also skipped any error handling and rollback.

Pour pouvoir exécuter ceci, nous utiliserons le plugin exec Maven pour appeler notre classe avec la configuration de classpath qui convient : `mvn exec:java -Dexec.mainClass="org.hibernate.tutorial.EventManager" -Dexec.args="store"`

## Note

Vous aurez sans doute besoin d'effectuer `mvn compile` pour commencer.

Vous devriez constater qu'Hibernate démarre et selon votre configuration, beaucoup de traces sur la sortie. À la fin, vous trouverez la ligne suivante :

    [java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)

C'est l' `INSERT` exécutée par Hibernate.

Maintenant nous aimerions aussi lister les événements stockés, donc nous ajoutons une option à la méthode principale :

            if (args[0].equals("store")) {

                mgr.createAndStoreEvent("My Event", new Date());

            }

            else if (args[0].equals("list")) {

                List events = mgr.listEvents();

                for (int i = 0; i < events.size(); i++) {

                    Event theEvent = (Event) events.get(i);

                    System.out.println(

                            "Event: " + theEvent.getTitle() + " Time: " + theEvent.getDate()

                    );

                }

            }

Nous ajoutons aussi une nouvelle méthode `listEvents()` :

        private List listEvents() {

            Session session = HibernateUtil.getSessionFactory().getCurrentSession();

            session.beginTransaction();

            List result = session.createQuery("from Event").list();

            session.getTransaction().commit();

            return result;

        }

Here, we are using a Hibernate Query Language (HQL) query to load all existing `Event` objects from the database. Hibernate will generate the appropriate SQL, send it to the database and populate `Event` objects with the data. You can create more complex queries with HQL. See Chapitre 16, HQL : langage d'interrogation d'Hibernate for more information.

Nous pouvons maintenant appeler notre nouvelle fonctionnalité, en utilisant à nouveau le plugin exec Maven : `mvn exec:java -Dexec.mainClass="org.hibernate.tutorial.EventManager" -Dexec.args="list"`

## 1.2. Section 2 - Mapper des associations

Pour l'instant, nous nous sommes contentés de mapper une classe d'une entité persistante vers une table. Profitons-en pour ajouter quelques associations de classe. D'abord nous ajouterons des gens à notre application, et stockerons une liste d'événements auxquels ils participent.

### 1.2.1. Mapper la classe Person

La première version de la classe `Person` est simple :

    package org.hibernate.tutorial.domain;

    public class Person {

        private Long id;

        private int age;

        private String firstname;

        private String lastname;

        public Person() {}

        // Accessor methods for all properties, private setter for 'id'

    }

A sauvegarder dans le fichier nommé `src/main/java/org/hibernate/tutorial/domain/Person.java`

Puis, créez le nouveau fichier de mappage `src/main/resources/org/hibernate/tutorial/domain/Person.hbm.xml`

    <hibernate-mapping package="org.hibernate.tutorial.domain">

        <class name="Person" table="PERSON">

            <id name="id" column="PERSON_ID">

                <generator class="native"/>

            </id>

            <property name="age"/>

            <property name="firstname"/>

            <property name="lastname"/>

        </class>

    </hibernate-mapping>

Finalement, ajoutez le nouveau mappage à la configuration d'Hibernate :

    <mapping resource="org/hibernate/tutorial/domain/Event.hbm.xml"/>

    <mapping resource="org/hibernate/tutorial/domain/Person.hbm.xml"/>

Nous allons maintenant créer une association entre ces deux entités. Évidemment, des personnes peuvent participer aux événements, et des événements ont des participants. Les questions de conception que nous devons traiter sont : direction, cardinalité et comportement de la collection.

### 1.2.2. Une association unidirectionnelle basée sur Set

Nous allons ajouter une collection d'événements à la classe `Person`. De cette manière nous pouvons facilement naviguer dans les événements d'une personne particulière, sans exécuter une requête explicite - en appelant `aPerson.getEvents()`. Nous utilisons une collection Java, un `Set`, parce que la collection ne contiendra pas d'éléments dupliqués et l'ordre ne nous importe pas pour ces exemples :

    public class Person {

        private Set events = new HashSet();

        public Set getEvents() {

            return events;

        }

        public void setEvents(Set events) {

            this.events = events;

        }

    }

D'abord nous mappons cette association, mais pensez à l'autre côté. Clairement, nous pouvons la laisser unidirectionnelle. Ou bien, nous pourrions créer une autre collection sur `Event`, si nous voulons être capable de la parcourir de manière bidirectionnelle. Ce n'est pas nécessaire d'un point de vue fonctionnel. Vous pourrez toujours exécuter une requête explicite pour récupérer les participants d'un évènement particulier. Vous êtes libre de choisir la conception, ce qui est certain, c'est que la cardinalité de l'association : "plusieurs" valués des deux côtés, est appelée plusieurs-à-plusieurs. Par conséquent nous utilisons un mappage Hibernate plusieurs-à-plusieurs :

    <class name="Person" table="PERSON">

        <id name="id" column="PERSON_ID">

            <generator class="native"/>

        </id>

        <property name="age"/>

        <property name="firstname"/>

        <property name="lastname"/>

        <set name="events" table="PERSON_EVENT">

            <key column="PERSON_ID"/>

            <many-to-many column="EVENT_ID" class="Event"/>

        </set>

    </class>

Hibernate supporte toutes sortes de mappage de collection, un `set` étant le plus commun. Pour une association plusieurs-à-plusieurs (ou une relation d'entité n:m), une table d'association est requise. Chaque ligne dans cette table représente un lien entre une personne et un événement. Le nom de la table est configuré avec l'attribut `table` de l'élément `set`. Le nom de la colonne identifiant dans l'association, du côté de la personne, est défini avec l'élément `key`, et le nom de la colonne pour l'événement avec l'attribut `column` de `many-to-many`. Vous devez aussi donner à Hibernate la classe des objets de votre collection (c'est-à-dire : la classe de l'autre côté de la collection).

Le schéma de base de données pour ce mappage est donc :

        _____________        __________________
       |             |      |                  |       _____________
       |   EVENTS    |      |   PERSON_EVENT   |      |             |
       |_____________|      |__________________|      |    PERSON   |
       |             |      |                  |      |_____________|
       | *EVENT_ID   | <--> | *EVENT_ID        |      |             |
       |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  |
       |  TITLE      |      |__________________|      |  AGE        |
       |_____________|                                |  FIRSTNAME  |
                                                      |  LASTNAME   |
                                                      |_____________|

### 1.2.3. Travailler avec l'association

Réunissons quelques personnes et quelques événements dans une nouvelle méthode dans `EventManager` :

        private void addPersonToEvent(Long personId, Long eventId) {

            Session session = HibernateUtil.getSessionFactory().getCurrentSession();

            session.beginTransaction();

            Person aPerson = (Person) session.load(Person.class, personId);

            Event anEvent = (Event) session.load(Event.class, eventId);

            aPerson.getEvents().add(anEvent);

            session.getTransaction().commit();

        }

Après le chargement d'une `Person` et d'un `Event`, modifiez simplement la collection en utilisant les méthodes normales de la collection. Comme vous pouvez le constater, il n'y a pas d'appel explicite à `update()` ou `save()`, Hibernate détecte automatiquement que la collection a été modifiée et a besoin d'être mise à jour. Ceci est appelé la vérification sale automatique (automatic dirty checking), et vous pouvez aussi l'essayer en modifiant le nom ou la propriété date de n'importe lequel de vos objets. Tant qu'ils sont dans un état persistant, c'est-à-dire, liés à une `Session` Hibernate particulière (c-à-d qu'ils ont juste été chargés ou sauvegardés dans une unité de travail), Hibernate surveille les changements et exécute le SQL correspondants. Le processus de synchronisation de l'état de la mémoire avec la base de données, généralement seulement à la fin d'une unité de travail, est appelé flushing. Dans notre code, l'unité de travail s'achève par un commit (ou rollback) de la transaction avec la base de données.

Vous pourriez bien sûr charger une personne et un événement dans différentes unités de travail. Ou vous modifiez un objet à l'extérieur d'une `Session`, s'il n'est pas dans un état persistant (s'il était persistant avant, nous appelons cet état détaché). Vous pouvez même modifier une collection lorsqu'elle est détachée :

        private void addPersonToEvent(Long personId, Long eventId) {

            Session session = HibernateUtil.getSessionFactory().getCurrentSession();

            session.beginTransaction();

            Person aPerson = (Person) session

                    .createQuery("select p from Person p left join fetch p.events where p.id = :pid")

                    .setParameter("pid", personId)

                    .uniqueResult(); // Eager fetch the collection so we can use it detached

            Event anEvent = (Event) session.load(Event.class, eventId);

            session.getTransaction().commit();

            // End of first unit of work

            aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached

            // Begin second unit of work

            Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();

            session2.beginTransaction();

            session2.update(aPerson); // Reattachment of aPerson

            session2.getTransaction().commit();

        }

L'appel à `update` rend un objet détaché à nouveau persistant, vous pourriez dire qu'il le lie à une nouvelle unité de travail, ainsi toutes les modifications que vous avez faites pendant qu'il était détaché peuvent être sauvegardées dans la base de données, cela inclut toute modification effectuées sur une collection de cet objet entité.

Cela n'a pas grand intérêt dans notre situation, mais c'est un concept important qu'il vous faut concevoir dans votre application. Pour le moment, complétez cet exercice en ajoutant une nouvelle action à la méthode principale de l'`EventManager` et invoquez-la depuis la ligne de commande. Si vous avez besoin des identifiants d'un client et d'un évènement - la méthode `save()` vous les retourne (vous devrez peut-être modifier certaines méthodes précédentes pour retourner ces identifiants) :

            else if (args[0].equals("addpersontoevent")) {

                Long eventId = mgr.createAndStoreEvent("My Event", new Date());

                Long personId = mgr.createAndStorePerson("Foo", "Bar");

                mgr.addPersonToEvent(personId, eventId);

                System.out.println("Added person " + personId + " to event " + eventId);

            }

C'était un exemple d'une association entre deux classes de même importance, deux entités. Comme mentionné plus tôt, il y a d'autres classes et d'autres types dans un modèle typique, généralement "moins importants". Vous en avez déjà vu certains, comme un `int` ou une `String`. Nous appelons ces classes des types de valeur, et leurs instances dépendent d'une entité particulière. Des instances de ces types n'ont pas leur propre identité, elles ne sont pas non plus partagées entre des entités (deux personnes ne référencent pas le même objet `firstname`, même si elles ont le même prénom). Bien sûr, des types de valeur n'existent pas seulement dans le JDK (en fait, dans une application Hibernate toutes les classes du JDK sont considérées comme des types de valeur), vous pouvez aussi écrire vous-même des classes dépendantes, `Address` ou `MonetaryAmount`, par exemple.

Vous pouvez aussi concevoir une collection de types de valeur. C'est conceptuellement très différent d'une collection de références vers d'autres entités, mais très ressemblant dans Java.

### 1.2.4. Collection de valeurs

Ajoutons un ensemble d'adresses email à l'entité `Person` qui sera représenté en tant que `java.util.Set` d'instance `java.lang.String` :

        private Set emailAddresses = new HashSet();

        public Set getEmailAddresses() {

            return emailAddresses;

        }

        public void setEmailAddresses(Set emailAddresses) {

            this.emailAddresses = emailAddresses;

        }

Le mappage de ce `Set` :

            <set name="emailAddresses" table="PERSON_EMAIL_ADDR">

                <key column="PERSON_ID"/>

                <element type="string" column="EMAIL_ADDR"/>

            </set>

La différence comparée au mappage vu plus tôt est la partie `element`, qui indique à Hibernate que la collection ne contient pas de référence vers une autre entité, mais une collection d'éléments de type `String` (le nom en minuscule vous indique que c'est un type/convertisseur du mappage Hibernate). Une fois encore, l'attribut `table` de l'élément `set` détermine le nom de la table pour la collection. L'élément `key` définit le nom de la colonne de la clé étrangère dans la table de la collection. L'attribut `column` dans l'élément `element` définit le nom de la colonne où les valeurs de `String` seront réellement stockées.

Considérons le schéma mis à jour :

      _____________        __________________
     |             |      |                  |       _____________
     |   EVENTS    |      |   PERSON_EVENT   |      |             |       ___________________
     |_____________|      |__________________|      |    PERSON   |      |                   |
     |             |      |                  |      |_____________|      | PERSON_EMAIL_ADDR |
     | *EVENT_ID   | <--> | *EVENT_ID        |      |             |      |___________________|
     |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  | <--> |  *PERSON_ID       |
     |  TITLE      |      |__________________|      |  AGE        |      |  *EMAIL_ADDR      |
     |_____________|                                |  FIRSTNAME  |      |___________________|
                                                    |  LASTNAME   |
                                                    |_____________|

Vous pouvez voir que la clé primaire de la table de la collection est en fait une clé composée, utilisant les deux colonnes. Ceci implique aussi qu'il ne peut pas y avoir d'adresses email dupliquées par personne, ce qui est exactement la sémantique dont nous avons besoin pour un ensemble dans Java.

Vous pouvez maintenant tester et ajouter des éléments à cette collection, juste comme nous l'avons fait auparavant en liant des personnes et des événements. C'est le même code dans Java.

        private void addEmailToPerson(Long personId, String emailAddress) {

            Session session = HibernateUtil.getSessionFactory().getCurrentSession();

            session.beginTransaction();

            Person aPerson = (Person) session.load(Person.class, personId);

            // adding to the emailAddress collection might trigger a lazy load of the collection

            aPerson.getEmailAddresses().add(emailAddress);

            session.getTransaction().commit();

        }

Cette fois-ci, nous n'avons pas utilisé de requête de chargement fetch pour initialiser la collection. Traquez les logs SQL et tentez d'optimiser ce cas avec un chargement agressif.

### 1.2.5. Associations bidirectionnelles

Ensuite nous allons mapper une association bidirectionnelle - faire fonctionner l'association entre une personne et un événement à partir des deux côtés dans Java. Bien sûr, le schéma de la base de données ne change pas, nous avons toujours une pluralité plusieurs-à-plusieurs.

## Note

Une base de données relationnelle est plus flexible qu'un langage de programmation réseau, donc elle n'a pas besoin de direction de navigation - les données peuvent être vues et récupérées de toutes les manières possibles.

D'abord, ajoutez une collection de participants à la classe `Event` :

        private Set participants = new HashSet();

        public Set getParticipants() {

            return participants;

        }

        public void setParticipants(Set participants) {

            this.participants = participants;

        }

Maintenant mappez ce côté de l'association aussi, dans `Event.hbm.xml`.

            <set name="participants" table="PERSON_EVENT" inverse="true">

                <key column="EVENT_ID"/>

                <many-to-many column="PERSON_ID" class="Person"/>

            </set

    >

Comme vous le voyez, ce sont des mappages de `set`s normaux dans les deux documents de mappage. Notez que les noms de colonne dans `key` et `many-to-many` sont inversés dans les 2 documents de mappage. L'ajout le plus important ici est l'attribut `inverse="true"` dans l'élément `set` du mappage de la collection des `Event`s.

Cela signifie que Hibernate devrait prendre l'autre côté - la classe `Person` - quand il a besoin de trouver des informations à propos du lien entre les deux. Ce sera beaucoup plus facile à comprendre une fois que vous verrez comment le lien bidirectionnel entre les deux entités est créé.

### 1.2.6. Travailler avec des liens bidirectionnels

Premièrement, gardez à l'esprit qu'Hibernate n'affecte pas la sémantique normale de Java. Comment avons-nous créé un lien entre une `Person` et un `Event` dans l'exemple unidirectionnel? Nous avons ajouté une instance de `Event` à la collection des références d'événement d'une instance de `Person`. Donc, évidemment, si vous voulons rendre ce lien bidirectionnel, nous devons faire la même chose de l'autre côté, en ajoutant une référence de `Person` à la collection dans un `Event`. Cette "configuration du lien des deux côtés" est absolument nécessaire et vous ne devriez jamais oublier de le faire.

Beaucoup de développeurs programment de manière défensive et créent des méthodes de gestion de lien pour affecter correctement les deux côtés, par exemple dans `Person` :

        protected Set getEvents() {

            return events;

        }

        protected void setEvents(Set events) {

            this.events = events;

        }

        public void addToEvent(Event event) {

            this.getEvents().add(event);

            event.getParticipants().add(this);

        }

        public void removeFromEvent(Event event) {

            this.getEvents().remove(event);

            event.getParticipants().remove(this);

        }

Notez que les méthodes get et set pour la collection sont maintenant protégées - ceci permet aux classes et aux sous-classes du même paquetage d'accéder aux méthodes, mais empêche quiconque de mettre le désordre directement dans les collections (enfin, presque). Vous devriez probablement faire de même avec la collection de l'autre côté.

Et à propos de l'attribut de mappage `inverse` ? Pour vous, et pour Java, un lien bidirectionnel consiste simplement à configurer correctement les références des deux côtés. Hibernate n'a cependant pas assez d'informations pour ordonner correctement les expressions SQL `INSERT` et `UPDATE` (pour éviter les violations de contrainte), et a besoin d'aide pour gérer proprement les associations bidirectionnelles. Rendre `inverse` un côté de l'association, indique à Hibernate de l'ignorer, pour le considérer comme un miroir de l'autre côté. Cela suffit à Hibernate pour gérer tous les problèmes de transformation d'un modèle de navigation directionnelle vers un schéma SQL de base de données. Les règles dont vous devez vous souvenir sont : toutes les associations bidirectionnelles ont besoin d'un côté marqué `inverse`. Dans une association un-à-plusieurs ce doit être le côté plusieurs, dans une association plusieurs-à-plusieurs, vous pouvez choisir n'importe quel côté, il n'y pas de différence.

## 1.3. Section 3 - L'application web EventManager

Une application web Hibernate utilise la `Session` et `Transaction` comme une application autonome. Cependant, quelques modèles communs sont utiles. Nous allons coder une `EventManagerServlet`. Ce servlet peut lister tous les évènements stockés dans la base de données, et fournir une formulaire HTML pour saisir de nouveaux évènements.

### 1.3.1. Écrire la servlet de base

Tout d'abord, nous devons créer notre servlet de base. La servlet n'accepte que les requêtes HTTP `GET`, la méthode à implémenter est donc `doGet()` :

    package org.hibernate.tutorial.web;

    // Imports

    public class EventManagerServlet extends HttpServlet {

        protected void doGet(

                HttpServletRequest request,

                HttpServletResponse response) throws ServletException, IOException {

            SimpleDateFormat dateFormatter = new SimpleDateFormat( "dd.MM.yyyy" );

            try {

                // Begin unit of work

                HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction();

                // Process request and render page...

                // End unit of work

                HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().commit();

            }

            catch (Exception ex) {

                HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().rollback();

                if ( ServletException.class.isInstance( ex ) ) {

                    throw ( ServletException ) ex;

                }

                else {

                    throw new ServletException( ex );

                }

            }

        }

    }

Servir la servlet en tant que `src/main/java/org/hibernate/tutorial/web/EventManagerServlet.java`

Le modèle appliqué ici est appelé session-per-request. Lorsqu'une requête appelle la servlet, une nouvelle `Session` Hibernate est ouverte à la première invocation de `getCurrentSession()` sur la `SessionFactory`. Ensuite, une transaction avec la base de données est démarrée - tous les accès à la base de données interviennent au sein de la transaction, peu importe que les données soient lues ou écrites (nous n'utilisons pas le mode auto-commit dans les applications).

N'utilisez pas une nouvelle `Session` Hibernate pour chaque opération en base de données. Utilisez une `Session` Hibernate qui porte sur l'ensemble de la requête. Utlisez `getCurrentSession()`, ainsi elle est automatiquement attachée au thread Java courant.

Ensuite, les actions possibles de la requêtes sont exécutées et la réponse HTML est rendue. Nous y reviendrons ultérieurement.

Enfin, l'unité de travail s'achève lorsque l'exécution et le rendu sont achevés. Si un problème survient lors de ces deux phases, une exception est lancée et la transaction avec la base de données subit un rollback. Cela complète le modèle `session-per-request`. Au lieu d'avoir un code de délimitant les transactions au sein de chaque servlet, vous pouvez écrire un filtre de servlet. Voir le site Hibernate et le Wiki pour plus d'informations sur ce modèle, appelé Open Session in View - vous en aurez besoin dès que vous utiliserez des JSP et non des servlets pour le rendu de vos vues.

### 1.3.2. Traiter et interpréter

Implémentons l'exécution de la requête et le rendu de la page.

            // Write HTML header

            PrintWriter out = response.getWriter();

            out.println("<html><head><title>Event Manager</title></head><body>");

            // Handle actions

            if ( "store".equals(request.getParameter("action")) ) {

                String eventTitle = request.getParameter("eventTitle");

                String eventDate = request.getParameter("eventDate");

                if ( "".equals(eventTitle) || "".equals(eventDate) ) {

                    out.println("<b><i>Please enter event title and date.</i></b>");

                }

                else {

                    createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));

                    out.println("<b><i>Added event.</i></b>");

                }

            }

            // Print page

           printEventForm(out);

           listEvents(out, dateFormatter);

           // Write HTML footer

           out.println("</body></html>");

           out.flush();

           out.close();

Ce style de code avec une mixture de Java et d'HTML ne serait pas extensible dans une application plus complexe - gardez à l'esprit que nous ne faisons qu'illustrer les concepts basiques de Hibernate dans ce didacticiel. Ce code affiche une entête et un pied de page HTML. Dans cette page, sont affichés un formulaire pour la saisie d'évènements ainsi qu'une liste de tous les évènements de la base de données. La première méthode est triviale et ne fait que sortir de l'HTML :

        private void printEventForm(PrintWriter out) {

            out.println("<h2>Add new event:</h2>");

            out.println("<form>");

            out.println("Title: <input name='eventTitle' length='50'/><br/>");

            out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>");

            out.println("<input type='submit' name='action' value='store'/>");

            out.println("</form>");

        }

La méthode `listEvents()` utilise la `Session` Hibernate liée au thread courant pour exécuter la requête :

        private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) {

            List result = HibernateUtil.getSessionFactory()

                    .getCurrentSession().createCriteria(Event.class).list();

            if (result.size() > 0) {

                out.println("<h2>Events in database:</h2>");

                out.println("<table border='1'>");

                out.println("<tr>");

                out.println("<th>Event title</th>");

                out.println("<th>Event date</th>");

                out.println("</tr>");

                Iterator it = result.iterator();

                while (it.hasNext()) {

                    Event event = (Event) it.next();

                    out.println("<tr>");

                    out.println("<td>" + event.getTitle() + "</td>");

                    out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>");

                    out.println("</tr>");

                }

                out.println("</table>");

            }

        }

Enfin, l'action `store` renvoie à la méthode `createAndStoreEvent()`, qui utilise aussi la `Session` du thread courant:

        protected void createAndStoreEvent(String title, Date theDate) {

            Event theEvent = new Event();

            theEvent.setTitle(title);

            theEvent.setDate(theDate);

            HibernateUtil.getSessionFactory()

                    .getCurrentSession().save(theEvent);

        }

La servlet est complétée. Une requête à la servlet sera exécutée par une seule `Session` et `Transaction`. Comme dans l'application autonome vue auparavant, Hibernate peut automatiquement lier ces objets au thread courant d'exécution. Cela vous laisse la liberté de séparer votre code en couches et d'accéder à la `SessionFactory` selon le moyen que vous aurez choisi. Généralement, vous utiliserez des conceptions plus sophistiquées et déplacerez le code d'accès aux données dans une couche DAO. Consultez le wiki Hibernate pour plus d'exemples.

### 1.3.3. Déployer et tester

Pour déployer cette application en vue de procéder à des tests, nous devons créer un WAR (Web ARchive). Tout d'abord, nous devons définir le descripteur WAR en tant que `src/main/webapp/WEB-INF/web.xml`

    <?xml version="1.0" encoding="UTF-8"?>

    <web-app version="2.4"

        xmlns="http://java.sun.com/xml/ns/j2ee"

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

        <servlet>

            <servlet-name>Event Manager</servlet-name>

            <servlet-class>org.hibernate.tutorial.web.EventManagerServlet</servlet-class>

        </servlet>

        <servlet-mapping>

            <servlet-name>Event Manager</servlet-name>

            <url-pattern>/eventmanager</url-pattern>

        </servlet-mapping>

    </web-app>

Pour construire et déployer, appelez `ant war` dans votre projet et copiez le fichier `hibernate-tutorial.war` dans le répertoire `webapp` de Tomcat.

## Note

If you do not have Tomcat installed, download it from http://tomcat.apache.org/ and follow the installation instructions. Our application requires no changes to the standard Tomcat configuration.

Une fois l'application déployée et Tomcat lancé, accédez à l'application via `http://localhost:8080/hibernate-tutorial/eventmanager`. Assurez vous de consulter les traces Tomcat pour observer l'initialisation d'Hibernate à la première requête touchant votre servlet (l'initialisation statique dans `HibernateUtil` est invoquée) et pour vérifier qu'aucune exception ne survienne.

## 1.4. Résumé

Ce didacticiel a couvert les bases de l'écriture d'une simple application Hibernate ainsi qu'une petite application web. Vous trouverez des tutoriels supplémentaires dans le site Hibernate website.

Copyright © 2004 Red Hat, Inc.

- PrécédentPréface
- Niveau supérieur
- Sommaire
- SuivantChapitre 2. Architecture