Container Managed Persistence контексты
При использовании управляемого контейнера сохраняемости контекстов (как вы через @PersistenceContext аннотаций), спецификация JPA определяет, что только один контекст сохранения может быть связан с транзакцией JTA.
Контекст сохранения создается контейнером Java EE. Несмотря на появление кода (аннотации @PersistenceContext, похоже, предполагают, что ПК вводится непосредственно в переменные экземпляра EntityManager), контекст персистентности фактически хранится в качестве ссылки WITHIN JTA TRANSACTION. Каждый раз, когда происходит операция EntityManager, она не ссылается на собственный внутренний контекст сохранения. Вместо этого он выполняет специальную операцию, поскольку управляется контейнером - он всегда ищет контекст персистентности в транзакции JTA и использует это. Это называется распространением контекста сохранения JTA.
Некоторые Цитаты из JPA спецификации:
Когда контейнер управляемого менеджер объекта используется, жизненный цикл контекста настойчивости всегда управляются автоматически, прозрачно для приложения, и контекста постоянства распространяется с транзакцией JTA .
Контейнер управляемых транзакции в области видимости Стойкость Контекст
... нового контекст сохранения начинается, когда контейнер управляемого диспетчер объектов вызываются [76] в рамках активной транзакции JTA, и существует контекст текущей стойкости, уже связанный с транзакцией JTA . Контекст сохранения создается, а затем связан с транзакцией JTA.
Контейнер управляемого Extended персистенции Context
... Контейнер управляемого расширенный контекст сохранения может быть инициирован только в рамках из сессионного компонента. Он существует с того момента, когда бит состояния с состоянием , который объявляет зависимость от диспетчера сущности типа PersistenceContextType.EXTENDED , создается и, как говорят, привязан к сеансовому компоненту с состоянием. Зависимость от расширенного контекста постоянных объявлений объявляется с помощью дескриптора дескриптора PersistenceContext или persistence-context-ref. Контекст сохранения закрывается контейнером при завершении метода @Remove сеансового компонента stateful (или экземпляр компонента состояния stateful в противном случае уничтожается).
Требования к Persistence Контекст распространения
... Если компонент называется и нет никакой транзакции JTA ..., контекст живучесть не распространяется. • Вызов менеджера объектов, определенного с помощью параметра PersistenceContext- . Type.TRANSACTION приведет к использованию нового контекста персистентности. • Вызов менеджера объектов, определенного в PersistenceContext- . Тип.EXTENDED приведет к использованию существующего расширенного контекста постоянства , связанного с этим компонентом.
... Если компонент вызывается и транзакция JTA распространяется на этот компонент: • Если компонент представляет собой сеансовый компонент с состоянием, к которому был привязан расширенный контекст персистентности, и существует другой контекст постоянства, связанный с транзакция JTA, исключение EJBException выбрано контейнером. • В противном случае, если существует контекст постоянства, связанный с транзакцией JTA, этот контекст персистентности распространяется и используется.
Это ваша проблема. Очевидный вопрос в $ 64: ПОЧЕМУ spec спрашивает об этом ???
Ну, это потому, что это преднамеренный компромисс, который приносит мощные магии EntityManager для EJB.
Использование транзакций JTA для распространения одного контекста постоянства имеет ограничение: транзакции не могут охватывать несколько контекстов постоянства, поэтому не могут охватывать несколько баз данных.
Однако это также имеет огромное преимущество: любой entityManager, объявленный в EJB, может автоматически обмениваться одним и тем же контекстом персистентности и, следовательно, может работать с одним и тем же набором объектов JPA и участвовать в одной транзакции. У вас может быть цепочка EJB, вызывающая другие EJB любой сложности, и все они ведут себя разумно и последовательно против данных сущности JPA.И им также не нужна сложность последовательной инициализации/обмена ссылками диспетчера объектов между вызовами метода - EntityManager может быть объявлен конфиденциально в каждом методе. Логика реализации может быть очень простой.
Ответ на ваш вопрос: Использование Применение управляемого Постоянство контексты (с помощью приложения управляемого EntityManagers)
Объявить свой EntityManager с помощью одного из этих подходов:
// "Java EE style" declaration of EM
@PersistenceUnit(unitName="H2PU")
EntityManagerFactory emfH2;
EntityManager emH2 = emfH2.createEntityManager();
ИЛИ
// "JSE style" declaration of EM
EntityManagerFactory emfH2 = javax.persistence.Persistence.createEntityManagerFactory("H2PU");
EntityManager emH2 = emfH2.createEntityManager();
and the same for emfOracle & emOracle.
Вы должны называть em.close(), когда вы закончите с каждым EM - предпочтительнее через окончательный { } или с помощью инструкции Java 7 try-with-resources.
Управляемые приложением ЭМ все еще участвуют (например, синхронизируются с) транзакциями JTA. Любое количество управляемых приложениями EM может участвовать в одной транзакции JTA, но ни один из них никогда не будет иметь свой контекст персистентности, связанный или распространяемый с любым управляемым контейнером EM.
Если EntityManager создается вне контекста транзакции JTA (до сделки началась), то вы должны спросить его в явной форме присоединиться к транзакции JTA:
// must be run from within Java EE code scope that already has a JTA
// transaction active:
em.joinTransaction();
Или еще проще, если EntityManager является созданный в контексте транзакции JTA, тогда EntityManager, управляемый приложениями, автоматически присоединяется к импликации транзакций JTA - нет необходимости в joinTransaction().
Таким образом, управляемые EM могут иметь транзакцию JTA, которая охватывает несколько баз данных. Конечно, вы можете всегда запустить локальный ресурс JDBC транзакций независимо от JTA:
EntityTransaction tx = em.getTransaction();
tx.begin();
// ....
tx.commit();
EDIT: дополнительные деталей управления транзакциями с применением управляемого Entity Менеджерами
ВНИМАНИЕ: образцами коды ниже для образовательное использование. Я набрал их с головы до головы, чтобы помочь объяснить мои очки. & не успели скомпилировать/отладить/протестировать.
Параметр @TransactionManagement по умолчанию для EJB - TransactionManagement.CONTAINER, а параметр по умолчанию @TransactionAttribute для методов EJB - TransactionAttribute.REQUIRED.
Есть четыре перестановки для управления транзакциями:
A) EJB с контейнером, управляемые JTA транзакции
Это предпочтительный подход Java EE.
EJB class @TransactionManagement аннотация:
должен автоматически указывать TransactionManagement.CONTAINER или опускать его, чтобы неявно использовать значение по умолчанию.
EJB метод @TransactionAttribute аннотация: должен быть установлен в TransactionAttribute.REQUIRED явно или опустить его для импликации использовать значение по умолчанию. (Примечание. Если у вас был другой бизнес-сценарий, вы можете использовать TransactionAttribute.MANDATORY или TransactionAttribute.REQUIRES_NEW, если их семантика соответствует вашим потребностям.)
Менеджеры управления приложениями:
они должны быть созданы с помощью Persistence.createEntityManagerFactory ("unitName") и emf.createEntityManager(), как описано выше.
Присоединиться к EntityManager с транзакцией JTA:
Создайте EntityManager WITHON для транзакционного метода EJB, и они автоматически присоединятся к транзакции JTA. ИЛИ если EntityManagers создаются заранее, вызовите em.joinTransaction() в рамках метода EJB транзакции.
Вызов EntityManager.close(), когда вы закончите использовать их. Это должно быть все, что требуется.
Основные примеры - просто использовать больше EntityManagers для сделки по нескольким БД:
@Stateless
public class EmployeeServiceBean implements EmployeeService {
// Transactional method
public void createEmployee() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService");
EntityManager em = emf.createEntityManager();
Employee emp = ...; // set some data
// No need for manual join - em created in active tx context, automatic join:
// em.joinTransaction();
em.persist(emp);
// other data & em operations ...
// call other EJBs to partake in same transaction ...
em.close(); // Note: em can be closed before JTA tx committed.
// Persistence Context will still exist & be propagated
// within JTA tx. Another EM instance could be declared and it
// would propagate & associate the persistence context to it.
// Some time later when tx is committed [at end of this
// method], Data will still be flushed and committed and
// Persistence Context removed .
emf.close();
}
}
@Stateful
public class EmployeeServiceBean implements EmployeeService {
// Because bean is stateful, can store as instance vars and use in multiple methods
private EntityManagerFactory emf;
private EntityManager em;
@PostConstruct // automatically called when EJB constructed and session starts
public void init() {
emf = Persistence.createEntityManagerFactory("EmployeeService");
em = emf.createEntityManager();
}
// Transactional method
public void createEmployee() {
Employee emp = ...; // set some data
em.joinTransaction(); // em created before JTA tx - manual join
em.persist(emp);
}
// Transactional method
public void updateEmployee() {
Employee emp = em.find(...); // load the employee
// don't do join if both methods called in same session - can only call once:
// em.joinTransaction(); // em created before JTA tx - manual join
emp.set(...); // change some data
// no persist call - automatically flushed with commit
}
@Remove // automatically called when EJB session ends
public void cleanup() {
em.close();
emf.close();
}
// ...
}
B) EJB с BEAN удалось JTA транзакции
Использование @ TransactionManagement.BEAN.
Внедрение интерфейса JTA UserTransaction, поэтому компонент может непосредственно отмечать транзакции JTA.
Ручная маркировка/синхронизация транзакции через UserTransaction.begin()/commit()/rollback().
Убедитесь, что EntityManager присоединяется к транзакции JTA - либо создайте EM в активном контексте транзакции JTA, либо вызовите em.joinTransaction().
Примеры:
@TransactionManagement(TransactionManagement.BEAN)
@Stateless
public class EmployeeServiceBean implements EmployeeService {
// inject the JTA transaction interface
@Resource UserTransaction jtaTx;
public void createEmployee() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService");
EntityManager em = emf.createEntityManager();
try {
jtaTx.begin();
try {
em.joinTransaction();
Employee emp = ...; // set some data
em.persist(emp);
// other data & em operations ...
// call other EJBs to partake in same transaction ...
} finally {
jtaTx.commit();
}
} catch (Exception e) {
// handle exceptions from UserTransaction methods
// ...
}
Employee emp = ...; // set some data
// No need for manual join - em created in active tx context, automatic join:
// em.joinTransaction();
em.persist(emp);
em.close(); // Note: em can be closed before JTA tx committed.
// Persistence Context will still exist inside JTA tx.
// Data will still be flushed and committed and Persistence
// Context removed some time later when tx is committed.
emf.close();
}
}
С) POJO/Non-EJB с ручной закодированы (рожкового управляемые) ресурсов локальных операций (не ССТ)
Просто использовать интерфейс JPA EntityTransaction для ТХ демаркации (полученный через em.getTransaction()).
Пример:
public class ProjectServlet extends HttpServlet {
@EJB ProjectService bean;
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// ...
try {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPU");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
bean.assignEmployeeToProject(projectId, empId);
bean.updateProjectStatistics();
} finally {
tx.commit();
}
} catch (Exception e) {
// handle exceptions from EntityTransaction methods
// ...
}
// ...
}
}
D) POJO/Non-EJB с ручной закодированы (POJO управляемого) ССТ сделок
Это предполагает POJO/компонент работает в каком-то контейнере, который имеет JTA поддержка.
Если в контейнере Java EE можно использовать вложение ресурсов Java EE интерфейса JTA UserTransaction.
(. В качестве альтернативы, можно явно LookUp дескриптор интерфейса ССТ и делать демаркацию на нем, а затем вызвать em.getTransaction() joinTransaction() - см JTA спецификации.)
Пример:
public class ProjectServlet extends HttpServlet {
@Resource UserTransaction tx;
@EJB ProjectService bean;
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// ...
try {
tx.begin();
try {
bean.assignEmployeeToProject(projectId, empId);
bean.updateProjectStatistics();
EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPU");
EntityManager em = emf.createEntityManager();
// Should be able to avoid explicit call to join transaction.
// Should automatically join because EM created in active tx context.
// em.joinTransaction();
// em operations on data here
em.close();
emf.close();
} finally {
tx.commit();
}
} catch (Exception e) {
// handle exceptions from UserTransaction methods
// ...
}
// ...
}
}
Это просто ошибка копирования или вхождение в имя '@ PercencyContext'? Должно ли это быть «FenixRadarPU»? – Magnilex
Это ошибка копирования. Я уже исправил это. Спасибо! –
Добавьте '@PersistenceContext (unitName =" ... ")' аннотации непосредственно в 'EntityManager' в классе 'Service', чтобы попытаться определить, является ли это проблемой CDI или проблемой JPA. –