Java Platform, Enterprise Edition (Java EE) 8
Учебник по Java EE

Назад Вперёд Содержание

Управление сущностями

Сущности управляются entity manager-ом, который представлен объектами javax.persistence.EntityManager. Каждый объект EntityManager связан с контекстом персистентности: набором объектов сущностей, которые существуют в хранилище данных. Контекст персистентности определяет область, в которой создаются, сохраняются и удаляются объекты сущностей. Интерфейс EntityManager определяет методы, которые используются для взаимодействия с контекстом персистентности.

Здесь рассматриваются следующие темы:

Интерфейс EntityManager

API EntityManager создаёт и удаляет объекты сущностей, осуществляет выборку объектов сущности по первичному ключу сущности и позволяет выполнять запросы к сущностям.

Здесь рассматриваются следующие темы:

Управляемые контейнером Entity Manager-ы

С помощью Entity Manager-а, управляемого контейнером, контекст персистентности объекта EntityManager автоматически распространяется контейнером на все компоненты приложения, которые используют объект EntityManager в рамках единого API транзакций Java (JTA).

Транзакции JTA обычно включают вызовы между компонентами приложения. Для завершения транзакции JTA этим компонентам обычно требуется доступ к одному контексту персистентности. Это происходит, когда EntityManager инъецируется в компоненты приложения посредством аннотации javax.persistence.PersistenceContext. Контекст персистентности автоматически распространяется с текущей транзакцией JTA, а ссылки EntityManager, которые сопоставлены с одним и тем же юнитом персистентности, обеспечивают доступ к контексту персистентности в этой транзакции. Благодаря автоматическому распространению (propagating) контекста персистентности компонентам приложения не нужно передавать ссылки на объекты EntityManager друг другу, чтобы вносить изменения в одной транзакции. Контейнер Java EE управляет жизненным циклом entity manager-ов, управляемых контейнером.

Чтобы получить объект EntityManager, инъецируйте EntityManager в компонент приложения:

@PersistenceContext
EntityManager em;

Управляемые приложением Entity Manager-ы

С другой стороны, с помощью entity manager-а, управляемого приложением, контекст персистентности не распространяется на компоненты приложения, а жизненный цикл объектов EntityManager управляется приложением.

Управляемые приложением entity manager-ы используются, когда приложению необходим доступ к контексту персистентности, который не распространяется с транзакцией JTA через объекты EntityManager в конкретном юните персистентности. В этом случае каждый EntityManager создаёт новый изолированный контекст персистентности. EntityManager и связанный с ним контекст персистентности создаются и уничтожаются приложением явным образом. Они также используются, когда прямое инъецирование объектов EntityManager невозможно, поскольку объекты EntityManager не являются потокобезопасными. Объекты EntityManagerFactory являются потокобезопасными.

В этом случае приложения создают объекты EntityManager, используя метод createEntityManager из javax.persistence.EntityManagerFactory.

Чтобы получить объект EntityManager, сначала необходимо получить объект EntityManagerFactory, инъецировав его в компонент приложения аннотацией javax.persistence.PersistenceUnit:

@PersistenceUnit
EntityManagerFactory emf;

Затем получите EntityManager из объекта EntityManagerFactory:

EntityManager em = emf.createEntityManager();

Entity manager-ы, управляемые приложением, не распространяют автоматически контекст транзакции JTA. Такие приложения должны вручную получить доступ к менеджеру транзакций JTA и добавить информацию о разграничении транзакций при выполнении операций с объектами сущностей. Интерфейс javax.transaction.UserTransaction определяет методы для запуска, фиксации и отката транзакций. Инъецируйте объект UserTransaction, создав переменную объекта с аннотацией @Resource:

@Resource
UserTransaction utx;

Чтобы начать транзакцию, вызовите метод UserTransaction.begin. Когда все операции с объектами сущностей завершены, вызовите метод UserTransaction.commit для фиксации транзакции. Метод UserTransaction.rollback используется для отката текущей транзакции.

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

@PersistenceUnit
EntityManagerFactory emf;
EntityManager em;
@Resource
UserTransaction utx;
...
em = emf.createEntityManager();
try {
    utx.begin();
    em.persist(SomeEntity);
    em.merge(AnotherEntity);
    em.remove(ThirdEntity);
    utx.commit();
} catch (Exception e) {
    utx.rollback();
}

Выборка сущностей с помощью EntityManager

Метод EntityManager.find используется для выборки объектов из хранилища данных по их первичному ключу:

@PersistenceContext
EntityManager em;
public void enterOrder(int custID, CustomerOrder newOrder) {
    Customer cust = em.find(Customer.class, custID);
    cust.getOrders().add(newOrder);
    newOrder.setCustomer(cust);
}

Управление жизненным циклом объекта сущности

Объекты сущности управляются с помощью операций объекта EntityManager. Объекты сущностей могут находиться в одном из четырёх состояний: новое, управляемое (managed), отсоединённое (detached) или удалённое (removed).

  • Новые объекты сущностей ещё не сохранены в хранилище и не связаны с контекстом персистентности.

  • Управляемые объекта уже сохранены в хранилище и связаны с контекстом персистентности.

  • Отсоединённые объекты сущности сохранены в хранилище, но в настоящее время не связаны с контекстом персистентности.

  • Удалённые объекты сохранены в хранилище, связаны с контекстом персистентности и отмечены для удаления из хранилища.

Сохранение объектов сущности

Новые объекты сущностей становятся управляемыми и сохраняются в хранилище либо путём вызова метода persist, либо с помощью каскадной операции persist, вызываемой из связанных сущностей, которые имеют элементы cascade=PERSIST или cascade=ALL, установленные в аннотациях отношений. Это означает, что данные объекта сохраняются в базе данных, когда транзакция, связанная с операцией persist, завершена. Если объект уже управляется, операция persist игнорируется, хотя операция persist будет каскадно связана со связанными объектами, у которых элемент cascade установлен в PERSIST или ALL в аннотации отношений. Если persist вызывается для удалённого объекта, объект становится управляемым. Если объект отсоединён, тогда либо выполнение persist выбросит исключение IllegalArgumentException, либо фиксация транзакции завершится неудачно. Следующий метод выполняет операцию persist:

@PersistenceContext
EntityManager em;
...
public LineItem createLineItem(CustomerOrder order, Product product,
        int quantity) {
    LineItem li = new LineItem(order, product, quantity);
    order.getLineItems().add(li);
    em.persist(li);
    return li;
}

Операция persist распространяется на все объекты, связанные с вызывающим объектом, у которых для элемента cascade установлено значение ALL или PERSIST в аннотации отношений:

@OneToMany(cascade=ALL, mappedBy="order")
public Collection<LineItem> getLineItems() {
    return lineItems;
}

Удаление объектов сущности

Управляемые объекты сущностей удаляются путём вызова метода remove или каскадной операции remove, вызываемой из связанных сущностей, которые имеют cascade=REMOVE или cascade=ALL в аннотации отношений. Если метод remove вызывается для нового объекта, операция remove игнорируется, хотя remove будет каскадно переходить к связанным объектам, которые имеют элемент cascade, установленный в значение REMOVE или ALL в аннотации отношения. Если remove вызывается для отсоединённого объекта, то либо remove сгенерирует IllegalArgumentException, либо фиксация транзакции завершится неудачно. Если вызывается для уже удалённого объекта, remove будет игнорироваться. Данные сущности будут удалены из хранилища после завершения транзакции или в результате операции flush.

В следующем примере все объекты LineItem, связанные с заказом, также удаляются, так как CustomerOrder.getLineItems имеет cascade=ALL, установленный в аннотации отношения:

public void removeOrder(Integer orderId) {
    try {
        CustomerOrder order = em.find(CustomerOrder.class, orderId);
        em.remove(order);
    }...

Синхронизация данных объекта сущности с базой данных

Состояние сохранённых объектов синхронизируется с базой данных, когда транзакция, с которой связан этот объект, фиксируется. Если управляемый объект находится в двунаправленном отношении с другим управляемым объектом, данные будут сохранены в зависимости от стороны-владельца отношения.

Чтобы принудительно синхронизировать управляемый объект с хранилищем данных, вызовите метод flush объекта EntityManager. Если объект связан с другим объектом, а аннотация отношения имеет элемент cascade, установленный в PERSIST или ALL, данные связанного объекта будут синхронизированы с хранилищем данных при вызове flush.

Если объект удаляется, вызов flush удалит данные объекта из хранилища данных.

Юниты персистентности

Юнит персистентности определяет набор всех классов сущностей, которые управляются объектами EntityManager в приложении. Этот набор классов сущностей представляет данные, содержащиеся в одном хранилище данных.

Юниты персистентности определяются в файле конфигурации persistence.xml. Ниже приведён пример файла persistence.xml:

<persistence>
    <persistence-unit name="OrderManagement">
        <description>This unit manages orders and customers.
            It does not rely on any vendor-specific features and can
            therefore be deployed to any persistence provider.
        </description>
        <jta-data-source>jdbc/MyOrderDB</jta-data-source>
        <jar-file>MyOrderApp.jar</jar-file>
        <class>com.widgets.CustomerOrder</class>
        <class>com.widgets.Customer</class>
    </persistence-unit>
</persistence>

Этот файл определяет персистентный модуль с именем OrderManagement, который использует источник данных jdbc/MyOrderDB с поддержкой JTA. Элементы jar-file и class определяют управляемые классы: классы сущностей, встраиваемые классы и сопоставленные родительские классы. Элемент jar-file определяет JAR-файлы, которые видны упакованному юниту персистентности, которые содержат управляемые классы сущностей, тогда как элементы class перечисляют управляемые классы сущностей явным образом.

Элементы jta-data-source (для источников данных, поддерживающих JTA) и non-jta-data-source (для источников данных, не поддерживающих JTA) задают глобальные имя JNDI источника данных, который будет использоваться контейнером.

JAR-файл или каталог, в каталоге META-INF которого содержится persistence.xml, называется корнем юнита персистентности. Область видимости юнита персистентности определяется корнем юнита персистентности. Каждый юнит персистентности идентифицируется по имени, уникальному для области видимости юнита персистентности.

Юниты персистентности могут быть упакованы как часть файла WAR или EJB JAR или как файл JAR, который затем может быть включён в WAR-файл или EAR.

  • Если вы упакуете юнит персистентности как набор классов в файле EJB JAR, persistence.xml должен быть помещён в каталог META-INF EJB JAR.

  • Если вы упакуете юнит персистентности как набор классов в файле WAR, файл persistence.xml должен находиться в каталоге WEB-INF/classes/META-INF файла WAR.

  • Если вы упакуете юнит персистентности в файл JAR, который будет включён в WAR-файл или EAR, файл JAR должен находиться в одном из следующих каталогов

    • Каталог WEB-INF/lib WAR

    • Каталог одной из библиотек EAR-файла

      Замечание:

      В Java Persistence API 1.0 файлы JAR могут находиться в корне файла EAR в качестве корня юнита персистентности. Это больше не поддерживается. Переносимые приложения должны использовать каталог библиотеки EAR-файла в качестве корня юнита персистентности.


Назад Вперёд Содержание
Логотип Oracle  Copyright © 2017, Oracle и/или её дочерних компаний. Все права защищены. Версия перевода 1.0.5 (Java EE Tutorial — русскоязычная версия)