1. Introducción
EntityManager es parte de la API de persistencia de Java. Principalmente, implementa las interfaces de programación y las reglas del ciclo de vida definidas por la especificación JPA 2.0.
Además, podemos acceder al contexto de persistencia, utilizando las API en EntityManager .
En este tutorial, veremos la configuración, los tipos y varias API de EntityManager .
2. Dependencias de Maven
Primero, necesitamos incluir las dependencias de Hibernate:
org.hibernate hibernate-core 5.4.0.Final
También tendremos que incluir las dependencias del controlador, dependiendo de la base de datos que estemos usando:
mysql mysql-connector-java 8.0.13
Las dependencias hibernate-core y mysql-connector-java están disponibles en Maven Central.
3. Configuración
Ahora, demostremos el EntityManager , usando una entidad Movie que corresponda a una tabla MOVIE en la base de datos.
A lo largo de este artículo, usaremos la API EntityManager para trabajar con los objetos Movie en la base de datos.
3.1. Definiendo la entidad
Comencemos por crear la entidad correspondiente a la tabla MOVIE, usando la anotación @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. El archivo persistence.xml
Cuando se crea EntityManagerFactory , la implementación de persistencia busca el archivo META-INF / persistence.xml en la ruta de clase .
Este archivo contiene la configuración para EntityManager :
Hibernate EntityManager Demo com.baeldung.hibernate.pojo.Movie true
Para explicarlo, definimos la unidad de persistencia que especifica el almacén de datos subyacente administrado por EntityManager .
Además, definimos el dialecto y las otras propiedades JDBC del almacén de datos subyacente. Hibernate es independiente de la base de datos. Basado en estas propiedades, Hibernate se conecta con la base de datos subyacente.
4. EntityManager administrado por contenedores y aplicaciones
Básicamente, hay dos tipos de EntityManager : administrado por contenedor y administrado por aplicación.
Echemos un vistazo más de cerca a cada tipo.
4.1. EntityManager administrado por contenedor
Aquí, el contenedor inyecta EntityManager en nuestros componentes empresariales.
En otras palabras, el contenedor crea EntityManager desde EntityManagerFactory para nosotros:
@PersistenceContext EntityManager entityManager;
Esto también significa que el contenedor está a cargo de comenzar la transacción, así como de confirmarla o revertirla.
Del mismo modo, el contenedor es responsable de cerrar EntityManager, por lo que es seguro de usarsin limpiezas manuales. Incluso si intentamos cerrar un EntityManager administrado por contenedor , debería lanzar una IllegalStateException.
4.2. EntityManager administrado por aplicaciones
Por el contrario, el ciclo de vida de EntityManager lo gestiona la aplicación aquí.
De hecho, crearemos manualmente EntityManager. Además, también gestionaremos el ciclo de vida del EntityManager que hemos creado.
Primero, creemos EntityManagerFactory:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.baeldung.movie_catalog");
Para crear un EntityManager , debemos llamar explícitamente a createEntityManager () en EntityManagerFactory :
public static EntityManager getEntityManager() { return emf.createEntityManager(); }
Dado que somos responsables de crear instancias de EntityManager , también es nuestra responsabilidad cerrarlas . Por lo tanto, deberíamos cerrar cada EntityManager cuando terminemos de usarlos.
4.3. Seguridad del hilo
Las instancias de EntityManagerFactory y, en consecuencia, las instancias de SessionFactory de Hibernate son seguras para subprocesos . Por lo que es completamente seguro en contextos concurrentes escribir:
EntityManagerFactory emf = // fetched from somewhere EntityManager em = emf.createEntityManager();
Por otro lado, las instancias de EntityManager no son seguras para subprocesos y están diseñadas para usarse en entornos confinados a subprocesos . Esto significa que cada hilo debe obtener su instancia, trabajar con ella y cerrarla al final.
Cuando se utilizan EntityManager administrados por aplicaciones , es fácil crear instancias confinadas a subprocesos:
EntityManagerFactory emf = // fetched from somewhere EntityManager em = emf.createEntityManager(); // use it in the current thread
Sin embargo, las cosas se vuelven contrarias a la intuición cuando se utilizan EntityManager administrados por contenedores . Por ejemplo:
@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.
Como siempre, el código utilizado en el artículo está disponible en Github.