У нас есть некоторый боб EJB не сохраняющий состояние JavaEE5, который передает введенный EntityManager его помощникам.
Действительно ли это безопасно? Это работало хорошо до сих пор, но я узнал некоторый документ Oracle, который указывает, что его реализация EntityManager ориентирована на многопотоковое исполнение. Теперь интересно, был ли причина, у нас не было проблем до сих пор, то, только потому, что реализация, которую мы использовали, оказалось, была ориентирована на многопотоковое исполнение (мы используем Oracle).
@Stateless
class SomeBean {
@PersistenceContext
private EntityManager em;
private SomeHelper helper;
@PostConstruct
public void init(){
helper = new SomeHelper(em);
}
@Override
public void business(){
helper.doSomethingWithEm();
}
}
На самом деле это имеет смысл.. Если бы EntityManager небезопасен потоком, контейнер должен был бы сделать
inercept business()
this.em = newEntityManager();
business();
который не распространит к его классам помощника.
Если так, какова лучшая практика в этом своего рода ситуация? Передача EntityManagerFactory вместо EntityManager?
Править: Этот вопрос очень интересен поэтому, если Вы интересуетесь этим вопросом, Вы, вероятно, хотите проверить этого, также:
Спецификация Править: Подробнее. ejb3.0
4.7.11 Неповторно используемые Экземпляры контейнер должен гарантировать, что только один поток может выполнять экземпляр в любое время. Если клиентский запрос прибывает для экземпляра, в то время как экземпляр выполняет другой запрос, контейнер может бросить javax.ejb. ConcurrentAccessException второму клиенту [24]. Если клиентское EJB 2.1 представление используется, контейнер может бросить java.rmi. RemoteException к второму запросу, если клиент является удаленным клиентом или javax.ejb. EJBException, если клиент является локальным клиентом. [25] Примечание, что объект сессии предназначается для поддержки только единственного клиента. Поэтому это была бы ошибка приложения, если бы два клиента попытались вызвать тот же объект сессии. Одна импликация этого правила - то, что приложение не может сделать вызовы петлевой проверки к бобовому экземпляру сессии.
И,
4.3.2 Внедрение зависимости боб сессии может использовать механизмы внедрения зависимости для получения ссылок на ресурсы или другие объекты в его среде (см. Главу 16, “Среда Компонента уровня предприятия”). Если боб сессии использует внедрение зависимости, контейнер вводит эти ссылки после того, как бобовый экземпляр создается, и прежде чем любые бизнес-методы будут вызваны на бобовый экземпляр. Если зависимость от SessionContext объявляется, или если класс компонента реализует дополнительный интерфейс SessionBean (см. Раздел 4.3.5), SessionContext также введен в это время. Если внедрение зависимости перестало работать, бобовый экземпляр отбрасывается. Под EJB 3.0 API класс компонента может получить интерфейс SessionContext посредством внедрения зависимости, не имея необходимость реализовывать интерфейс SessionBean. В этом случае аннотация Ресурса (или resource-env-ref элемент дескриптора развертывания) используется для обозначения зависимости боба от SessionContext. См. Главу 16, “Среда Компонента уровня предприятия”.
Я использовал похожую схему, но хелпер создавался в @PostConstruct
, а инжектируемый менеджер сущностей передавался в конструктор в качестве параметра. Каждый экземпляр EJB имел свой собственный хелпер, и тогда гарантировалась потокобезопасность.
У меня также был вариант, когда менеджер сущностей не инжектировался (потому что EJB вообще его не использовал), поэтому хелпер должен был искать его с помощью InitialContext
. В этом случае контекст персистентности все равно должен быть "импортирован" в родительский EJB с помощью @PersistenceContext
:
@Stateless
@PersistenceContext(name="OrderEM")
public class MySessionBean implements MyInterface {
@Resource SessionContext ctx;
public void doSomething() {
EntityManager em = (EntityManager)ctx.lookup("OrderEM");
...
}
}
Но на самом деле проще инжектировать его (даже если EJB его не использует), чем искать его, особенно для тестируемости.
Но чтобы вернуться к вашему основному вопросу, я думаю, что менеджер сущностей, который инжектируется или просматривается, является оберткой, которая переадресует к основному активному менеджеру сущностей, который привязан к транзакции.
Надеюсь, это поможет.
EDIT
Разделы § 3.3 и § 5.6 в спецификации немного освещают эту тему.
Я использовал вспомогательные методы и передавал туда EntityManager
, и все в порядке.
Так что я бы рекомендовал либо передавать его в методы, когда это необходимо, либо сделать хелпер самим бобом, инжектировать его (используя @EJB
) и инжектировать туда EntityManager
.