|
|
<table>
|
|
|
<thead>
|
|
|
<tr>
|
|
|
<th width="200px"><h6>[:rewind: Exo Précédent](/Exo11-Transaction/1%5D-Code-Java)</h6></th>
|
|
|
<th colspan="4" width="600px"><h1 align="center">12 - Spring - Hibernate</h1></th>
|
|
|
<th width="200px"><h6 align="right">[Exo Suivant :fast_forward:](/Exo13-JPA/1%5D-Code-Java)</h6></th>
|
|
|
</tr>
|
|
|
</thead>
|
|
|
|
|
|
<tbody>
|
|
|
<tr>
|
|
|
<td> </td>
|
|
|
<td align="center">[:one:](/Exo12-Hibernate/1%5D-Code-Java)<br/>Code Java</td>
|
|
|
<td align="center">:white_check_mark:<br/>DAO ou Repository</td>
|
|
|
<td align="center">[:three:](/Exo12-Hibernate/3%5D-Services-métiers)<br/>Services métiers</td>
|
|
|
<td align="center">[:four:](/Exo12-Hibernate/4%5D-Le-Main-et-les-tests)<br/>Le Main et les tests</td>
|
|
|
<td> </td>
|
|
|
</tr>
|
|
|
</tbody>
|
|
|
|
|
|
<tfoot>
|
|
|
<tr align="right">
|
|
|
<td colspan="6">
|
|
|
<h6>:copyright: 2019 - <a href="mailto:admin@ferretrenaud.fr">FERRET Renaud</a></h6>
|
|
|
</td>
|
|
|
</tr>
|
|
|
</tfoot>
|
|
|
</table>
|
|
|
|
|
|
***
|
|
|
|
|
|
# Vue d'ensemble des DAO
|
|
|
Les [DAO](https://fr.wikipedia.org/wiki/Objet_d%27acc%C3%A8s_aux_donn%C3%A9es) (ou repository) sont les seules classes autorisées à envoyer des requêtes SQLs.
|
|
|
|
|
|
Chaque classe est représentée par son interface.
|
|
|
|
|
|
Toutes les classes ont comme parent `src\main\java\com\banque\dao\impl\AbstractDAO.java` qui est [abstraite](https://www.jmdoudoux.fr/java/dej/chap-poo.htm#poo-3-4) et [générique](https://www.jmdoudoux.fr/java/dej/chap-jdk1.5.htm#jdk1.5-6).
|
|
|
|
|
|
Les DAOs sont actuellement utilisés (et instanciés) par les services métiers et les tests unitaires.
|
|
|
|
|
|
Rappel : vous ne pourrez pas tester votre code tant que vous n'aurez pas fait toutes les modifications.
|
|
|
|
|
|
# Sortir les informations d'accès à la base
|
|
|
Les informations liées à la base de données sont dans le fichier `src\main\resources\hibernate\hibernate.cfg.xml`.
|
|
|
|
|
|
Créez un fichier properties qui va reprendre l'ensemble de ses informations, placez le où vous voulez.
|
|
|
|
|
|
Par exemple, `src\main\resources\spring\database.properties` :
|
|
|
|
|
|
```properties
|
|
|
db.driver=com.mysql.cj.jdbc.Driver
|
|
|
db.url=jdbc:mysql://localhost/banque?useSSL=false&serverTimezone=Europe/Paris
|
|
|
db.login=root
|
|
|
db.password=
|
|
|
|
|
|
# https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#configurations
|
|
|
hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
|
|
|
hibernate.connection.pool_size=20
|
|
|
hibernate.cache.provider_class=org.hibernate.cache.NoCacheProvider
|
|
|
hibernate.cache.use_second_level_cache=false
|
|
|
```
|
|
|
|
|
|
Vous pouvez changer les clefs si vous le désirez.
|
|
|
|
|
|
Rappel : **faites très attention**, n'ajoutez pas d'espaces ou de " dans les valeurs (à droite du signe =)
|
|
|
|
|
|
Supprimez le fichier de configuration Hibernate (fichier `src\main\resources\hibernate\hibernate.cfg.xml`)
|
|
|
|
|
|
## Classe com.banque.dao.AbstractDAO
|
|
|
Supprimez la classe Java `com.banque.util.HibernateSessionFactory` et le package `com.banque.util`.
|
|
|
|
|
|
Ajoutez à la classe *AbstractDAO* un attribut privé *sessionFactory* de type [org.hibernate.SessionFactory](https://docs.jboss.org/hibernate/orm/current/javadocs/org/hibernate/SessionFactory.html) et potentiellement des méthodes get/set.
|
|
|
|
|
|
Modifiez le code en conséquence, supprimez l'attribut *currentSession* de la classe AbstractDAO. Retirez aussi les méthodes `createSession()` , `setCurrentSession(Session pSession)` et `getCurrentSession()` de cette classe. N'oubliez pas de retirer de l'interface *IDAO* les deux méthodes `setCurrentSession(Session pSession)` et `createSession()`.
|
|
|
|
|
|
La méthode `handleTransaction` de *AbstractDAO* doit aussi disparaître, c'est le Spring qui se chargera de la mécanique transactionnelle.
|
|
|
|
|
|
C'est votre attribut *sessionFactory* qui devra vous fournir au besoin une variable locale de type [org.hibernate.Session](https://docs.jboss.org/hibernate/orm/current/javadocs/org/hibernate/Session.html) via la méthode `getCurrentSession()` de la SessionFactory.
|
|
|
|
|
|
Exemple de transformation :
|
|
|
|
|
|
```java
|
|
|
// Nouveau code
|
|
|
public T insert(T uneEntite) throws ExceptionDao {
|
|
|
if (uneEntite == null) {
|
|
|
return null;
|
|
|
}
|
|
|
try {
|
|
|
Session pSession = this.getSessionFactory().getCurrentSession();
|
|
|
pSession.save(uneEntite);
|
|
|
} catch (Exception e) {
|
|
|
throw new ExceptionDao(e);
|
|
|
}
|
|
|
return uneEntite;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Soyez **très attentif** au fait que l'on appelle la méthode [getCurrentSession()](https://docs.jboss.org/hibernate/orm/current/javadocs/org/hibernate/SessionFactory.html#getCurrentSession--) et non plus [openSession()](https://docs.jboss.org/hibernate/orm/current/javadocs/org/hibernate/SessionFactory.html#openSession--) de la [SessionFactory](https://docs.jboss.org/hibernate/orm/current/javadocs/org/hibernate/SessionFactory.html).
|
|
|
|
|
|
C'est le Spring qui va se charger du *close* de la session Hibernate, c'est pour cela que le bloque de finally est supprimé.
|
|
|
|
|
|
Ajustez le reste du code de la même manière.
|
|
|
|
|
|
# Déclaration des DAOs
|
|
|
Pour fonctionner nous devrons annoter nos classes métiers (DAOs+services) pour les confier au Spring
|
|
|
* [@Service](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Service.html)
|
|
|
* [@Repository](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Repository.html)
|
|
|
|
|
|
Il nous faudra aussi déclarer les 3 beans techniques suivants :
|
|
|
* Déclarer une dataSource
|
|
|
* Déclarer une sessionFactory
|
|
|
* Déclarer un TransactionManager
|
|
|
|
|
|
Et enfin, faire les injections de dépendances entre tous nos éléments :
|
|
|
* [@Autowired](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html)
|
|
|
|
|
|
Il faut maintenant confier nos DAOs à Spring. Selon votre choix de mode de fonctionnement Spring, sélectionnez une des solutions suivantes :
|
|
|
* Par fichier XML
|
|
|
* Par classe de configuration
|
|
|
|
|
|
Remarque : dans le cas d'Hibernate **pur**, il n'est pas du tout conseillé de faire usage de Spring Boot qui sait faire du JPA plus que de l'Hibernate.
|
|
|
|
|
|
Ajoutez l'annotation de classe [@Repository](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Repository.html) sur **tous** vos DAOs.
|
|
|
|
|
|
Ajoutez l'annotation [@Autowired](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html) sur l'attribut sessionFactory de votre AbstractDAO.
|
|
|
|
|
|
```java
|
|
|
@Repository
|
|
|
abstract class AbstractDAO<T extends IEntity> implements IDAO<T> {
|
|
|
|
|
|
@Autowired
|
|
|
private SessionFactory sessionFactory;
|
|
|
...
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## Par fichier XML - data-context.xml
|
|
|
Créez un fichier XML `src\main\resources\spring\data-context.xml`, inspirez vous des exercices précédents.
|
|
|
|
|
|
En Hibernate 4, la [sessionFactory](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/orm/hibernate5/LocalSessionFactoryBean.html) ressemblera à :
|
|
|
|
|
|
```xml
|
|
|
...
|
|
|
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
|
|
|
<property name="dataSource" ref="dataSource" />
|
|
|
<property name="mappingResources">
|
|
|
<list>
|
|
|
<value>hibernate/compte.hbm.xml</value>
|
|
|
<value>hibernate/operation.hbm.xml</value>
|
|
|
<value>hibernate/utilisateur.hbm.xml</value>
|
|
|
</list>
|
|
|
</property>
|
|
|
<property name="hibernateProperties">
|
|
|
<props>
|
|
|
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
|
|
|
<prop key="hibernate.connection.pool_size">${hibernate.connection.pool_size}</prop>
|
|
|
<prop key="hibernate.cache.provider_class">${hibernate.cache.provider_class}</prop>
|
|
|
<prop key="hibernate.cache.use_second_level_cache">${hibernate.cache.use_second_level_cache}</prop>
|
|
|
</props>
|
|
|
</property>
|
|
|
</bean>
|
|
|
...
|
|
|
```
|
|
|
|
|
|
En Hibernate 5, la [sessionFactory](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/orm/hibernate5/LocalSessionFactoryBean.html) ressemblera à :
|
|
|
|
|
|
```xml
|
|
|
...
|
|
|
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
|
|
|
<property name="dataSource" ref="dataSource" />
|
|
|
<property name="mappingResources">
|
|
|
<list>
|
|
|
<value>hibernate/compte.hbm.xml</value>
|
|
|
<value>hibernate/operation.hbm.xml</value>
|
|
|
<value>hibernate/utilisateur.hbm.xml</value>
|
|
|
</list>
|
|
|
</property>
|
|
|
<property name="hibernateProperties">
|
|
|
<props>
|
|
|
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
|
|
|
<prop key="hibernate.connection.pool_size">${hibernate.connection.pool_size}</prop>
|
|
|
<prop key="hibernate.cache.provider_class">${hibernate.cache.provider_class}</prop>
|
|
|
<prop key="hibernate.cache.use_second_level_cache">${hibernate.cache.use_second_level_cache}</prop>
|
|
|
</props>
|
|
|
</property>
|
|
|
</bean>
|
|
|
...
|
|
|
```
|
|
|
|
|
|
La déclaration du chargement du fichier properties est la même que dans l'exercice [6](/Exo06-Scope-et-context/2%5D-XML)
|
|
|
|
|
|
Le *component-scan* sera le même que dans l'exercice [8](/Exo08-Anotations/2%5D-XML).
|
|
|
|
|
|
Le bean DataSource est exactement le même que dans l'exercice [10](/Exo10-JDBC/2%5D-XML).
|
|
|
|
|
|
Vous ne devez pas déclarer vos beans DAOs, les annotations [@Repository](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Repository.html) s'en chargent.
|
|
|
|
|
|
## Par classe de configuration - SpringConfigurationData
|
|
|
Créez une classe de configuration Spring `src\main\java\com\banque\spring\SpringConfigurationData.java`, inspirez vous des exercices précédents.
|
|
|
|
|
|
En Hibernate 4, la [sessionFactory](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/orm/hibernate5/LocalSessionFactoryBean.html) ressemblera à :
|
|
|
|
|
|
```java
|
|
|
@Bean
|
|
|
public org.springframework.orm.hibernate4.LocalSessionFactoryBean sessionFactory(
|
|
|
DataSource dataSource,
|
|
|
@Value("${hibernate.dialect}") String dialect,
|
|
|
@Value("${hibernate.connection.pool_size}") Integer pSize,
|
|
|
@Value("${hibernate.cache.provider_class}") String cacheClass,
|
|
|
@Value("${hibernate.cache.use_second_level_cache}") Boolean useCache) {
|
|
|
|
|
|
org.springframework.orm.hibernate4.LocalSessionFactoryBean resu = new org.springframework.orm.hibernate4.LocalSessionFactoryBean();
|
|
|
resu.setDataSource(dataSource);
|
|
|
resu.setMappingResources("hibernate/compte.hbm.xml", "hibernate/operation.hbm.xml","hibernate/utilisateur.hbm.xml");
|
|
|
Properties hibernateProperties = new Properties();
|
|
|
hibernateProperties.put("hibernate.dialect", dialect);
|
|
|
hibernateProperties.put("hibernate.connection.pool_size", pSize);
|
|
|
hibernateProperties.put("hibernate.cache.provider_class", cacheClass);
|
|
|
hibernateProperties.put("hibernate.cache.use_second_level_cache", useCache);
|
|
|
resu.setHibernateProperties(hibernateProperties);
|
|
|
return resu;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
En Hibernate 5, la [sessionFactory](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/orm/hibernate5/LocalSessionFactoryBean.html) ressemblera à :
|
|
|
|
|
|
```java
|
|
|
@Bean
|
|
|
public org.springframework.orm.hibernate5.LocalSessionFactoryBean sessionFactory(
|
|
|
DataSource dataSource,
|
|
|
@Value("${hibernate.dialect}") String dialect,
|
|
|
@Value("${hibernate.connection.pool_size}") Integer pSize,
|
|
|
@Value("${hibernate.cache.provider_class}") String pCacheProviderClass,
|
|
|
@Value("${hibernate.cache.use_second_level_cache}") Boolean pUseSecondLevelCache) {
|
|
|
|
|
|
org.springframework.orm.hibernate5.LocalSessionFactoryBean resu = new org.springframework.orm.hibernate5.LocalSessionFactoryBean();
|
|
|
resu.setDataSource(dataSource);
|
|
|
resu.setMappingResources("hibernate/compte.hbm.xml", "hibernate/operation.hbm.xml","hibernate/utilisateur.hbm.xml");
|
|
|
Properties hibernateProperties = new Properties();
|
|
|
hibernateProperties.put("hibernate.dialect", dialect);
|
|
|
hibernateProperties.put("hibernate.connection.pool_size", pSize);
|
|
|
hibernateProperties.put("hibernate.cache.provider_class", pCacheProviderClass);
|
|
|
hibernateProperties.put("hibernate.cache.use_second_level_cache", pUseSecondLevelCache);
|
|
|
hibernateProperties.put("hibernate.hibernate.show_sql", Boolean.FALSE);
|
|
|
resu.setHibernateProperties(hibernateProperties);
|
|
|
return resu;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
La déclaration du chargement du fichier properties est la même que dans l'exercice [6](/Exo06-Scope-et-context/2%5D-Configuration)
|
|
|
|
|
|
Le *@ComponentScan* sera le même que dans l'exercice [8](/Exo08-Anotations/2%5D-Configuration).
|
|
|
|
|
|
Le bean DataSource est exactement le même que dans l'exercice [10](/Exo10-JDBC/2%5D-Configuration).
|
|
|
|
|
|
***
|
|
|
|
|
|
<table>
|
|
|
<thead>
|
|
|
<tr>
|
|
|
<th width="200px"><h6>[:rewind: Exo Précédent](/Exo11-Transaction/1%5D-Code-Java)</h6></th>
|
|
|
<th colspan="4" width="600px"><h1 align="center">12 - Spring - Hibernate</h1></th>
|
|
|
<th width="200px"><h6 align="right">[Exo Suivant :fast_forward:](/Exo13-JPA/1%5D-Code-Java)</h6></th>
|
|
|
</tr>
|
|
|
</thead>
|
|
|
|
|
|
<tbody>
|
|
|
<tr>
|
|
|
<td> </td>
|
|
|
<td align="center">[:one:](/Exo12-Hibernate/1%5D-Code-Java)<br/>Code Java</td>
|
|
|
<td align="center">:white_check_mark:<br/>DAO ou Repository</td>
|
|
|
<td align="center">[:three:](/Exo12-Hibernate/3%5D-Services-métiers)<br/>Services métiers</td>
|
|
|
<td align="center">[:four:](/Exo12-Hibernate/4%5D-Le-Main-et-les-tests)<br/>Le Main et les tests</td>
|
|
|
<td> </td>
|
|
|
</tr>
|
|
|
</tbody>
|
|
|
|
|
|
<tfoot>
|
|
|
<tr align="right">
|
|
|
<td colspan="6">
|
|
|
<h6>:copyright: 2019 - <a href="mailto:admin@ferretrenaud.fr">FERRET Renaud</a></h6>
|
|
|
</td>
|
|
|
</tr>
|
|
|
</tfoot>
|
|
|
</table> |