JPA

Java Persistance API

adriencaubel.fr

Limite de JDBC

  • Bas niveau => écriture de requête SQL
  • Duplication de code
    • ouverture connexion
    • requête
  • Connaître le moteur SGBD
    • e.g. LIMIT n'est pas du standard SQL mais MySQL

=> On souhaiterait une solution pour ne pas avoir à se soucier du SGBD

L'API JPA

alt

  • JPA n'est qu'une API dont l'utilisation nécessite une implémentation
  • S'appuie sur JDBC

https://docs.oracle.com/javaee/6/tutorial/doc/bnbpz.html

Le fichier persistence.xml

Le fichier persistence.xml contient la configuration de base pour le mapping notamment en fournissant les informations sur la connexion à la base de données à utiliser.
Il est stocké dans resources/META-INF/persitence.xml

Il contient :

  • Des propriétés génériques connues par JPA (url de connexion, user et password)
  • Des propriétés spécifiques à l’ORM choisi (ici Hibernate)

Le fichier persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence 
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
    <persistence-unit name="monapp-unit" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

        <properties>
            <!-- Configuring JDBC properties -->
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/monapp?useSSL=false" />
            <property name="javax.persistence.jdbc.user" value="user" />
            <property name="javax.persistence.jdbc.password" value="password" />

            <!-- Hibernate properties -->
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL8Dialect" />
            <property name="hibernate.hbm2ddl.auto" value="validate" />

            <!-- Configuring Connection Pool -->
            <property name="hibernate.dbcp.initialSize" value="5" />

            <!-- Set the cache provider -->
            <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
        </properties>
    </persistence-unit>
</persistence>

Exploiter le fichier

EntityManagerFactory emf = 
    Persistence.createEntityManagerFactory("monapp-unit"); // même nom

EntityManager em = emf.createEntityManager();

EntityManager

Les interactions entre la base de données et les beans entités sont assurées par un objet de type javax.persistence.EntityManager

Entity Manager

EntityManagerFactory emf = 
    Persistence.createEntityManagerFactory("monapp-unit"); // même nom

EntityManager em = emf.createEntityManager();

Entity Manager Opérations

// 1. Persist : Enregistrer une nouvelle entité
Person person = new Person("Alice", 25);
em.persist(person);

// 2. Find : Rechercher une entité par sa clé primaire
Person foundPerson = em.find(Person.class, person.getId());

// 3. Merge : Mettre à jour une entité détachée
Person detachedPerson = new Person("Bob", 30);
detachedPerson.setName("Updated Bob");
Person managedPerson = em.merge(detachedPerson);

Entity Manager Opérations

// 4. Remove : Supprimer une entité
em.remove(managedPerson);

// 5. Query : Exécuter une requête JPQL
List<Person> persons = em.createQuery("SELECT p FROM Person p", Person.class)
                         .getResultList();

Cycle de vie Entité JPA

alt text

Cycle de vie Entité JPA

// Etat new
Person person = new Person("John Doe");

// Etat managed (pas persisté en base)
em.persist(person);

// Les modifications apportées à une entité managée sont enregistrées dans le contexte de persistance, 
// mais elles ne sont  pas écrites en base tant que la transaction n'est pas validée.
person.setName("John Smith");

// L'entité est insérée dans la base à ce moment.
em.getTransaction().commit();

Cycle de vie Entité JPA - détaché

// Etat Managed (récupéré de la BDD)
Person foundPerson = em.find(Person.class, person.getId());

// Etat Detached - plus managée par l'EntityManager
em.detach(foundPerson);

// Seulement une modification in-memory sur l'objet foundPerson
// Le contexte de persistance ne suivra pas ce changement et il ne sera pas enregistré dans la base de données.
foundPerson.setName("John Smith");

// Comme aucun changement sur les entités managées, rien ne sera update en BDD
em.getTransaction().commit();
  • La modification réalisé sur foundPerson ne sera pas persistée car elle est réalisé sur une entité détachée.

Cycle de vie Entité JPA - détaché

Si on veut persister, nous devons rattacher l'entité en utilisant un merge()

Person updatedPerson = em.merge(foundPerson); // Reattaches the entity
updatedPerson.setName("John Smith");
em.getTransaction().commit();

Transactions

  • Transactions automatiques
    • Si on utilise un conteneur comme JavaEE comme TomEE ou Widfly ou un framework comme Spring

  • Transactions manuelles
    • Si on est en JAVA SE
    • => Transactions gérées par le EntityManager

Transactions manuelles

EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();  // Démarre une transaction

...
em.persist(entity);           // action
...

em.getTransaction().commit(); // Valide la transaction -> persiste en BDD
em.close();