Вопрос про многопоточность и EntityManager

Я разрабатываю свое веб-приложение, используя реализацию JPA 2.0 EclipseLink 2.2.0. Наконец-то мне удалось запустить многопоточный код, и я получил это исключение:

java.lang.IllegalStateException: Attempting to execute an operation on a closed EntityManager.

Объекты, которые имеют все вызовы javax.persistence в моем приложении, определяются как область приложения, например:

@Model
@ApplicationScoped
public class LocationControl implements Serializable {

    @PersistenceContext private EntityManager   em;
    @Resource           private UserTransaction utx;

    // etc

И, конечно же, все управляемые компоненты (обычно RequestScoped или ConversationScoped), которые хотят получить доступ к базе данных, делают это следующим образом:

@Inject private LocationControl lc;

Итак, мой вопрос заключается в следующем: получил ли я это исключение с помощью @ApplicationScoped DAO? Я думал, что так будет более эффективно, поскольку контейнеру не нужно будет постоянно воссоздавать этот объект при каждом запросе, если у него нет области действия, а у DAO нет собственного состояния. Однако если объекты EntityManager и UserTransaction должны быть отдельными экземплярами для каждого пользователя, это будет проблемой.

В качестве альтернативы я мог бы использовать синхронизированные методы DAO, но я думаю, что это приведет к блокировке потоков в контейнере (GlassFish).

Любые советы приветствуются.


person AlanObject    schedule 30.08.2011    source источник
comment
Я не занимаюсь CDI, но этот LocationControl обычно должен был быть @Stateless EJB и должен быть внедрен @EJB. Я не знаю, что означает @Model, но в бизнес-классе это плохо пахнет.   -  person BalusC    schedule 30.08.2011


Ответы (1)


Аннотация @Model изначально была создана для аннотирования bean-компонентов с областью действия запроса, вот как она определена:

@Named

@RequestScoped

@Stereotype

@Target({TYPE, METHOD, FIELD})

@Retention(RUNTIME)

public @interface Model {}

Конечно, вы можете переопределить «@RequestScoped» другой аннотацией, но «@ApplicationScoped» — это не лучший выбор, поскольку все в приложении изменят состояние одного и того же внедренного EntityManager. Я думаю, что в большинстве случаев было бы лучше оставить его @RequestScoped, иногда, например, для bean-компонента данных входа/выхода может быть вариант «@SessionScoped», но я не вижу сценария для дао «@ApplicationScoped».

Если вы вообще не хотите использовать @Model и используете полный контейнер Java EE, то EJB без сохранения состояния, как сказал BalusC, был бы отличным вариантом и для Dao.

person Kris    schedule 31.08.2011
comment
Я думаю, что мы отвлеклись на использование '@Model' здесь. На самом деле это расширение «@Named», и я преобразовываю свой код для использования «@Named». Но реальный вопрос заключается в том, могу ли я использовать один экземпляр DAO с его ссылкой на один EntityManager и UserTransaction с несколькими потоками или нет. - person AlanObject; 31.08.2011
comment
Даже если вы используете «@Named» вместо «@Model» и по-прежнему используете «@ApplicationScope», вы сделаете свой диспетчер сущностей глобальным, и, на мой взгляд, этого не должно быть. - person Kris; 01.09.2011
comment
Хорошо, я думаю, мне придется пойти с этим. Спасибо за ваш вклад. - person AlanObject; 02.09.2011