Guide du Hibernate EntityManager

1. Introduction

EntityManager fait partie de l'API Java Persistence. Principalement, il implémente les interfaces de programmation et les règles de cycle de vie définies par la spécification JPA 2.0.

De plus, nous pouvons accéder au contexte de persistance, en utilisant les API dans EntityManager .

Dans ce didacticiel, nous examinerons la configuration, les types et diverses API d' EntityManager .

2. Dépendances de Maven

Tout d'abord, nous devons inclure les dépendances d'Hibernate:

 org.hibernate hibernate-core 5.4.0.Final  

Nous devrons également inclure les dépendances du pilote, en fonction de la base de données que nous utilisons:

 mysql mysql-connector-java 8.0.13 

Les dépendances hibernate-core et mysql-connector-java sont disponibles sur Maven Central.

3. Configuration

Maintenant, démontrons EntityManager , en utilisant une entité Movie qui correspond à une table MOVIE dans la base de données.

Au cours de cet article, nous utiliserons l' API EntityManager pour travailler avec les objets Movie dans la base de données.

3.1. Définition de l'entité

Commençons par créer l'entité correspondant à la table MOVIE, à l'aide de l' annotation @Entity :

@Entity @Table(name = "MOVIE") public class Movie { @Id private Long id; private String movieName; private Integer releaseYear; private String language; // standard constructor, getters, setters }

3.2. Le fichier persistence.xml

Lorsque l' EntityManagerFactory est créé, l'implémentation de persistance recherche le fichier META-INF / persistence.xml dans le chemin de classe .

Ce fichier contient la configuration d' EntityManager :

 Hibernate EntityManager Demo com.baeldung.hibernate.pojo.Movie true         

Pour expliquer, nous définissons l'unité de persistance qui spécifie la banque de données sous-jacente gérée par EntityManager .

De plus, nous définissons le dialecte et les autres propriétés JDBC du magasin de données sous-jacent. Hibernate est indépendant de la base de données. Sur la base de ces propriétés, Hibernate se connecte à la base de données sous-jacente.

4. EntityManager géré par conteneur et application

Fondamentalement, il existe deux types d' EntityManager : géré par conteneur et géré par application.

Examinons de plus près chaque type.

4.1. EntityManager géré par conteneur

Ici, le conteneur injecte le EntityManager dans nos composants d'entreprise.

En d'autres termes, le conteneur crée l' EntityManager à partir de EntityManagerFactory pour nous:

@PersistenceContext EntityManager entityManager; 

Cela signifie également que le conteneur est chargé de commencer la transaction, ainsi que de la valider ou de la restaurer.

De même, le conteneur est responsable de la fermeture de EntityManager, il est donc sûr à utilisersans nettoyage manuel. Même si nous essayons de fermer un EntityManager géré par un conteneur , il doit lever une IllegalStateException.

4.2. EntityManager géré par les applications

Inversement, le cycle de vie de l' EntityManager est géré par l'application ici.

En fait, nous allons créer manuellement l' EntityManager. De plus, nous gérerons également le cycle de vie de l' EntityManager que nous avons créé.

Tout d'abord, créons l' EntityManagerFactory:

EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.baeldung.movie_catalog");

Afin de créer un EntityManager , nous devons appeler explicitement createEntityManager () dans EntityManagerFactory :

public static EntityManager getEntityManager() { return emf.createEntityManager(); }

Puisque nous sommes responsables de la création des instances EntityManager , il est également de notre responsabilité de les fermer . Par conséquent, nous devons fermer chaque EntityManager lorsque nous avons fini de les utiliser.

4.3. Fil-Sécurité

Les instances EntityManagerFactory et, par conséquent, les instances SessionFactory d'Hibernate , sont thread-safe . Il est donc totalement sûr d'écrire dans des contextes simultanés:

EntityManagerFactory emf = // fetched from somewhere EntityManager em = emf.createEntityManager();

D'autre part, les instances EntityManager ne sont pas thread-safe et sont destinées à être utilisées dans des environnements confinés au thread . Cela signifie que chaque thread doit obtenir son instance, travailler avec elle et la fermer à la fin.

Lorsque vous utilisez des EntityManager gérés par des applications , il est facile de créer des instances confinées au thread:

EntityManagerFactory emf = // fetched from somewhere EntityManager em = emf.createEntityManager(); // use it in the current thread

Cependant, les choses deviennent contre-intuitives lorsque vous utilisez des EntityManager gérés par des conteneurs . Par exemple:

@Service public class MovieService { @PersistenceContext // or even @Autowired private EntityManager entityManager; // omitted }

It seems that one EntityManager instance should be shared for all operations. However, the container (JakartaEE or Spring) injects a special proxy instead of a simple EntityManager here. Spring, for example, injects a proxy of type SharedEntityManagerCreator.

Every time we use the injected EntityManager, this proxy will either reuse the existing EntityManager or create a new one. Reuse usually occurs when we enable something like Open Session/EntityManager in View.

Either way, the container ensures that each EntityManager is confined to one thread.

5. Hibernate Entity Operations

The EntityManager API provides a collection of methods. We can interact with the database, by making use of these methods.

5.1. Persisting Entities

In order to have an object associated with the EntityManager, we can make use of the persist() method :

public void saveMovie() { EntityManager em = getEntityManager(); em.getTransaction().begin(); Movie movie = new Movie(); movie.setId(1L); movie.setMovieName("The Godfather"); movie.setReleaseYear(1972); movie.setLanguage("English"); em.persist(movie); em.getTransaction().commit(); }

Once the object is saved in the database, it is in the persistent state.

5.2. Loading Entities

For the purpose of retrieving an object from the database, we can use the find() method.

Here, the method searches by the primary key. In fact, the method expects the entity class type and the primary key:

public Movie getMovie(Long movieId) { EntityManager em = getEntityManager(); Movie movie = em.find(Movie.class, new Long(movieId)); em.detach(movie); return movie; }

However, if we just need the reference to the entity, we can use the getReference() method instead. In effect, it returns a proxy to the entity:

Movie movieRef = em.getReference(Movie.class, new Long(movieId));

5.3. Detaching Entities

In the event that we need to detach an entity from the persistence context, we can use the detach() method. We pass the object to be detached as the parameter to the method:

em.detach(movie);

Once the entity is detached from the persistence context, it will be in the detached state.

5.4. Merging Entities

In practice, many applications require entity modification across multiple transactions. For example, we may want to retrieve an entity in one transaction for rendering to the UI. Then, another transaction will bring in the changes made in the UI.

We can make use of the merge() method, for such situations. The merge method helps to bring in the modifications made to the detached entity, in the managed entity, if any:

public void mergeMovie() { EntityManager em = getEntityManager(); Movie movie = getMovie(1L); em.detach(movie); movie.setLanguage("Italian"); em.getTransaction().begin(); em.merge(movie); em.getTransaction().commit(); }

5.5. Querying for Entities

Furthermore, we can make use of JPQL to query for entities. We'll invoke getResultList() to execute them.

Of course, we can use the getSingleResult(), if the query returns just a single object:

public List queryForMovies() { EntityManager em = getEntityManager(); List movies = em.createQuery("SELECT movie from Movie movie where movie.language = ?1") .setParameter(1, "English") .getResultList(); return movies; }

5.6. Removing Entities

Additionally, we can remove an entity from the database using the remove() method. It's important to note that, the object is not detached, but removed.

Here, the state of the entity changes from persistent to new:

public void removeMovie() { EntityManager em = HibernateOperations.getEntityManager(); em.getTransaction().begin(); Movie movie = em.find(Movie.class, new Long(1L)); em.remove(movie); em.getTransaction().commit(); }

6. Conclusion

In this article, we have explored the EntityManager in Hibernate. We've looked at the types and configuration, and we learned about the various methods available in the API for working with the persistence context.

Comme toujours, le code utilisé dans l'article est disponible sur Github.