Рубрики
Без рубрики

Руководство по управлению EntityManager Hibernate

Взгляните на класс EntityManager и его использование в режиме гибернации

Автор оригинала: baeldung.

1. введение

EntityManager является частью API сохранения Java. В основном он реализует программные интерфейсы и правила жизненного цикла, определенные спецификацией JPA 2.0.

Кроме того, мы можем получить доступ к контексту сохранения, используя API в EntityManager .

В этом руководстве мы рассмотрим конфигурацию, типы и различные API-интерфейсы EntityManager .

2. Зависимости Maven

Во-первых, нам нужно включить зависимости Hibernate:


    org.hibernate
    hibernate-core
    5.4.0.Final

Нам также придется включить зависимости драйверов, в зависимости от базы данных, которую мы используем:


    mysql
    mysql-connector-java
    8.0.13

Зависимости hibernate-core и mysql-connector-java доступны в Maven Central.

3. Конфигурация

Теперь давайте продемонстрируем EntityManager , используя сущность Movie , которая соответствует таблице фильмов в базе данных.

В этой статье мы будем использовать API EntityManager для работы с объектами Movie в базе данных.

3.1. Определение сущности

Давайте начнем с создания сущности, соответствующей таблице ФИЛЬМОВ, используя аннотацию @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. persistence.xml Файл

При создании EntityManagerFactory реализация персистентности выполняет поиск META-INF/persistence.xml файл в пути к классу .

Этот файл содержит конфигурацию для EntityManager :


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

Чтобы объяснить это, мы определяем единицу сохранения, которая определяет базовое хранилище данных, управляемое EntityManager .

Кроме того, мы определяем диалект и другие свойства JDBC базового хранилища данных. Hibernate не зависит от базы данных. На основе этих свойств Hibernate подключается к базовой базе данных.

4. EntityManager, управляемый контейнером и приложением

В принципе, существует два типа EntityManager : Управляемый контейнером и управляемый приложением.

Давайте поближе рассмотрим каждый тип.

4.1. EntityManager, управляемый контейнером

Здесь контейнер вводит EntityManager в наши корпоративные компоненты.

Другими словами, контейнер создает EntityManager из EntityManagerFactory для нас:

@PersistenceContext
EntityManager entityManager;

Это также означает, что контейнер отвечает за начало транзакции, а также за ее фиксацию или откат.

Аналогично, контейнер отвечает за закрытие EntityManager, поэтому безопасно использовать без ручной очистки. Даже если мы попытаемся закрыть управляемый контейнером EntityManager , он должен вызвать исключение IllegalStateException.

4.2. EntityManager,управляемый приложением

И наоборот, жизненный цикл EntityManager управляется приложением здесь.

Фактически, мы вручную создадим EntityManager. Кроме того, мы также будем управлять жизненным циклом созданного EntityManager .

Во-первых, давайте создадим EntityManagerFactory:

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

Чтобы создать EntityManager , мы должны явно вызвать createEntityManager() в EntityManagerFactory :

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

Поскольку мы несем ответственность за создание экземпляров EntityManager , мы также несем ответственность за их закрытие|/. Поэтому мы должны закрыть каждый EntityManager , когда мы закончим их использовать.

4.3. Безопасность резьбы

Экземпляры EntityManagerFactory и, следовательно, экземпляры SessionFactory Hibernate являются потокобезопасными . Таким образом, в параллельных контекстах писать абсолютно безопасно:

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

С другой стороны, экземпляры EntityManager не являются потокобезопасными и предназначены для использования в средах с ограниченным потоком . Это означает, что каждый поток должен получить свой экземпляр, работать с ним и закрыть его в конце.

При использовании управляемого приложением EntityManager s легко создавать экземпляры, ограниченные потоками:

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

Однако при использовании управляемого контейнером EntityManager s все становится нелогичным. Например:

@Service
public class MovieService {

    @PersistenceContext // or even @Autowired
    private EntityManager entityManager;
    
    // omitted
}

Похоже, что один экземпляр EntityManager должен быть общим для всех операций. Однако контейнер (JakartaEE или Spring) вводит специальный прокси-сервер вместо простого EntityManager здесь . Spring, например, вводит прокси типа SharedEntityManagerCreator .

Каждый раз, когда мы используем введенный EntityManager, этот прокси будет либо повторно использовать существующий EntityManager , либо создавать новый. Повторное использование обычно происходит, когда мы включаем что-то вроде Open Session/EntityManager в представлении .

В любом случае, контейнер гарантирует, что каждый EntityManager ограничен одним потоком .

5. Операции с сущностями в режиме гибернации

API EntityManager предоставляет набор методов. Мы можем взаимодействовать с базой данных, используя эти методы.

5.1. Сохраняющиеся сущности

Для того, чтобы объект был связан с EntityManager, мы можем использовать метод persist() :

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();
}

Как только объект сохранен в базе данных, он находится в стойкий государство.

5.2. Загрузка объектов

Для извлечения объекта из базы данных мы можем использовать находить() метод.

Здесь метод выполняет поиск по первичному ключу. На самом деле метод ожидает тип класса сущности и первичный ключ:

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

Однако, если нам просто нужна ссылка на сущность, мы можем вместо этого использовать метод getReference () . По сути, он возвращает прокси-сервер сущности:

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

5.3. Отсоединение объектов

В случае, если нам нужно отделить сущность от контекста сохранения, мы можем использовать метод detach () //. Мы передаем объект для отсоединения в качестве параметра методу:

em.detach(movie);

Как только сущность будет отделена от контекста сохранения, она будет находиться в отделенном состоянии.

5.4. Слияние сущностей

На практике многие приложения требуют изменения сущности в нескольких транзакциях. Например, мы можем получить объект в одной транзакции для визуализации в пользовательском интерфейсе. Затем другая транзакция внесет изменения, внесенные в пользовательский интерфейс.

Для таких ситуаций мы можем использовать метод merge () . Метод слияния помогает внести изменения, внесенные в отдельный объект, в управляемый объект, если таковые имеются:

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. Запрос сущностей

Кроме того, мы можем использовать JPQL для запроса сущностей. Мы вызовем getResultList() для их выполнения.

Конечно, мы можем использовать getSingleResult(), если запрос возвращает только один объект:

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. Удаление сущностей

Кроме того, мы можем удалить объект из базы данных с помощью метода remove () //. Важно отметить, что объект не отсоединяется, а удаляется.

Здесь состояние сущности изменяется с постоянного на новое:

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. Заключение

В этой статье мы рассмотрели EntityManager в Спящий режим . Мы рассмотрели типы и конфигурацию, а также узнали о различных методах, доступных в API для работы с контекстом persistence.

Как всегда, код, используемый в статье, доступен на Github .