Hibernate
Hibernate est un framework Objet-Relationnel ayant comme but de cacher la complexité de la persistance aux développeurs Objet. L'un des avantages d'Hibernate est de pouvoir s'intégrer très facilement aussi bien dans un environnement managé (serveur d'application) que dans un environnement non managé (appli simple), contrairement aux entity bean qui demandent un serveur d'application.
Entity & Fichier de mapping
A partir d'un objet simple respectant la partie javabean (get et set) comme FactureStatut.java il faut créer un fichier de mapping factureStatut.hbm.xml dans le même répertoire que l'objet
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="ch.gma.test.hibernate.entity">
<class name="YBFactureStatutEntity" table="YBFACTURESTATUT">
<id name="uuid" column="UUID">
<generator class="uuid" />
</id>
<property name="noFacture" column="NOFACTURE" />
<property name="statut" column="CDSTATUT" />
<property name="dateEnvoi" column="DTENVOIYB" />
</class>
</hibernate-mapping>
Le choix du generator
TODO
Mapping à double d'une colonne
Pour mapper à double une colonne, il faut spécifier laquelle s'occupe de la mise à jour des données en utilisant les attributs update="false" et insert="false".
<property name="doublon" column="COLONNEMAPPEEADOUBLE" update="false" insert="false" /> <many-to-one name="colonneMappee" column="COLONNEMAPPEEADOUBLE" class="MaClasse" />
Relation entre 2 tables sans clé primaire
Pour spécifier une relation sur une colonne autre que la clé primaire, il faut utiliser les attributs property-ref et unique.
<!-- dans fichier primaire, simulation d'une clé primaire par une contrainte d'unicité --> <property name="cleUnique" column="UNIQUEKEY" unique="true" /> <!-- dans fichier étranger, simulation d'une relation par clé étrangère --> <many-to-one name="cleEtrangereSurUnique" column="FKUNIQUEKEY" class="NomClass" property-ref="cleUnique" />
Interface Session
Se trouve entre la connexion et la transaction. Elle permet de gérer l'état des objets se trouvant dans son pool, soit l'ensemble des opérations CRUD. Elle n'est pas ThreadSafe et doit dont rester la même pour un processus complet.
Interface SessionFactory
Permet d'obtenir des objet Session. Utilisée par plusieurs processus. Contient les infos de connexion à la base de données.
Pour associer la SessionFactory à un nom JNDI, il faut utiliser la propriété hibernate.session_factory_name (par ex: java:hibernate/SessionFactory). 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é.
Interface de Configuration
Permet de configurer et lancer Hibernate. Se base sur les fichiers de mapping objet-relationnel. Le fichier hibernate.cfg.xml contient ces informations.
<?xml version="1.0"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/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">create</property>
<mapping resource="ch/gma/test/hibernate/entity/ybFactureStatut.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Interface de Transaction
Pas obligatoire, elle permet de s'appuyer sur les transactions du serveur d'application via l'API JTA (Java Transaction API)
hibernate.transaction.factory_class
- org.hibernate.transaction.JDBCTransactionFactory: S'appuie sur la transaction JDBC courante (option par défaut)
- org.hibernate.transaction.JTATransactionFactory: Délègue à la transaction managée par le container s'il en existe une dans le context courant. Sinon, une nouvelle transaction est lancée.
- org.hibernate.transaction.CMTTTransactionFactory: Délègue à la transaction managée par le container.
hibernate.transaction.manager_lookup_class: Certaines fonctionnalités d'Hibernate dans un serveur d'application (cache 2° niveau, association auto entre transaction et session) requièrent un accès au manager de transaction JTA.
- org.hibernate.transaction.WebSphereTransactionManagerLookup: Pour WebSphere
- org.hibernate.transaction.WebSphereExtendedJTATransactionLookup: Pour WebSphere 6
Interfaces Query et Criteria
Permet de créer de requêtes vers la base de données.
Interface CallBack
Permettre à un objet "persistant" d'être notifié des différents événements effectués par le moteur de persistance Hibernate.
Interface Type
Gérer le mapping entre un attribut java et un type base de données. Il est possible de créer des types spécifiques.
Message d'erreurs et solutions
TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing
=> You might need to force a session flush between saving B and saving A in case the association doesn't have cascade.
=> Changer le style de l'attribut cascade ou splitter en deux la méthode.
org.springframework.orm.hibernate3.SessionFactoryUtils doClose Could not close Hibernate Session org.hibernate.SessionException: Session was already closed
=>
org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is org.hibernate.TransactionException: could not register synchronization with JTA TransactionManager
=>
org.hibernate.exception.SQLGrammarException: could not load an entity: [ch.gma.common.as400.entity.disponibilite.DisponibiliteBatch#NOVABATCH]
Caused by: java.sql.SQLException: [SQL5016] Nom d'objet qualifié IDPBATCH non admis.
=> Vérifier que la propriété hibernate hibernate.default_schema ne soit pas défini si utilisation d'une datasource JNDI.
Problèmes rencontrés
left join fetch retourne des doublons
Pour chaque ligne SQL, hibernate retourne une entité (dans la mémoire les objets ne sont pas dupliqués). Pour retourner des entités uniques, rajouter le code
query.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);