Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2013_1 / КСТ / Разработка веб-приложений.pdf
Скачиваний:
160
Добавлен:
23.02.2015
Размер:
2.74 Mб
Скачать

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

Некоторые поставщики Java Persistence API, включая поставщика «по умолчанию» Enterprise Server, требуют задания столбца дискриминатора в таблице, соответствующего корневой сущности при использовании стратегии присоединения подкласса. Если вы не используете автоматическое создание таблиц в вашем приложении, убедитесь, что база данных правильно устанавливает для столбца таблицы дискриминатора значение по умолчанию или использует аннотацию @DiscriminatorColumn, чтобы соответствовать схеме вашей базы данных.

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

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

Контекст хранения является множеством управляемых экземпляров сущностей, которое существует в конкретном хранилище данных.

Интерфейс EntityManager

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

Container-Managed Entity Managers

Управляемый контейнерным менеджером сущностей контекст хранения экземпляра EntityManager автоматически распространяется контейнером на все прикладные компоненты, которые используют экземпляр EntityManager в пределах одной транзакции Java Transaction Architecture (JTA) .

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

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

@PersistenceContext EntityManager em;

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

123

Менеджеры сущностей приложения используются приложением, когда нужно иметь доступ к контексту хранения, который не распространяется транзакцией 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();

Менеджеры объектов приложения не распространяют автоматически контекст

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

с сущностями. Интерфейс javax.transaction.UserTransaction определяет методы для

начала, завершения и отмены транзакции. Внедрите экземпляр UserTransaction, создавая переменную экземпляра, аннотированную @Resource.

@Resource UserTransaction utx;

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

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

@PersistenceContext 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();

}

124

Поиск сущностей с использованием EntityManager

Метод EntityManager.find используется для поиска сущностей с заданным пер-

вичным ключом.

@PersistenceContext EntityManager em;

public void enterOrder(int custID, Order newOrder) { Customer cust = em.find(Customer.class, custID); cust.getOrders().add(newOrder); newOrder.setCustomer(cust);

}

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

Вы управляете экземплярами сущности, выполняя операции на объекте мето-

дами экземпляра EntityManager. Экземпляры сущности находятся в одном из четырех

состояний: новый, управляемый, отделенный или удаленный.

Новые экземпляры сущности не имеют хранимого образа и еще не связаны

контекстом хранения.

Управляемые экземпляры сущности имеют хранимый образ и связаны контек-

стом хранения.

Отделенные экземпляры сущности имеют хранимый образ и к настоящему времени не связаны контекстом хранения.

Удаленные экземпляры сущности имеют хранимый образ, связаны контекстом хранения и запланированы для удаления из хранилища данных.

Хранимые экземпляры сущности

Новые экземпляры сущности становятся управляемыми и хранимыми вызовом

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

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

@PersistenceContext EntityManager em;

...

public LineItem createLineItem(Order order, Product product, int quantity) {

LineItem li = new LineItem(order, product, quantity); order.getLineItems().add(li);

em.persist(li); return li;

}

125

Операция persist распространится на все сущности, имеющие отношение к вы-

зывающей сущности, у которых установлен элемент cascade в ALL или PERSIST в

аннотации отношения.

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

return lineItems;

}

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

Управляющие экземпляры сущности удаляются вызовом метода remove

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

будет выполняться каскадно для связанных сущностей, которые имеют cascade-

элемент REMOVE или ALL в аннотации отношения. Если удаление выполняется для

отделённой сущности, оно возбудит исключение IllegalArgumentException, или завер-

шение транзакции потерпит неудачу. Если удаление выполняется для уже удаленной

сущности, оно будет проигнорировано. Данные будут удалены из хранилища, когда

завершается транзакция или в результате операции flush.

public void removeOrder(Integer orderId) { try {

Order order = em.find(Order.class, orderId); em.remove(order);

}...

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

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

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

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

Для того чтобы форсировать синхронизацию управляющего объекта в хранилище данных, вызовите метод flush экземпляра EntityManager. Если сущность обу-

словливается другой сущностью, и в аннотации отношения был установлен каскадный

элемент в PERSIST или ALL, связанные данные сущности будут синхронизированы с хранилищем данных, когда вызывается метод flush.

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

Модуль хранения

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

Модули хранения определены файлом конфигурации persistence.xml. Файл JAR или директория, чья директория МЕТА-INF содержит persistence.xml, называется

корнем модуля хранения. Область видимости модуля хранения определена корнем

хранилища.

126

Каждый модуль хранения должен называться уникальным именем в области

видимости.

Модули хранения могут быть упакованы как часть файла WAR или EJB JAR,

или же как файл JAR, который затем может быть включен в файл WAR или EJB JAR.

Если вы упаковываете модуль хранения как множество классов в файле EJB

JAR, persistence.xml должен быть вложен в папку META-INF архива EJB JAR.

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

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

в WEB-INF/lib архива WAR;

в папке библиотек /lib файла EAR .

Примечание. В Java Persistence API 1.0 файлы JAR могли быть располо-

жены в корне файла EAR как корень устройства хранения. Эта возможность устарела и больше не поддерживается. Портируемые приложения

должны использовать библиотечную директорию /lib файла EAR как корень модуля хранения.

Файл persistence.xml

Файл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.Order</class> <class>com.widgets.Customer</class>

</persistence-unit> </persistence>

Этот файл определяет модуль хранения с именем OrderManagement, которое

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

называет хранимые классы.

Элементы jta-data-source (для источников данных JTA) и non-jta-data-source

(не источники данных JTA) определяют глобальное имя JNDI источника данных, кото-

рое использует контейнер.

127

Соседние файлы в папке КСТ