2012-04-30 4 views
7

После построения компонента я хочу получить данные из базы данных с помощью EntityManager. Это невозможно в конструкторе, потому что EntityManager вводится после вызова конструктора. Поэтому я попытался сделать это в методе, аннотированном с @PostConstruct. Согласно API, после завершения инъекции вызывается метод PostConstruct. Выполнение запроса работает, но оно всегда возвращает пустой список. Если я использую тот же запрос в другом методе, он возвращает правильный результат. Кто-нибудь знает, почему это не работает в методе PostConstruct?EJB: Использование EntityManager в методе PostConstruct

@Stateful(mappedName = "price") 
@Singleton 
@Startup 
public class PriceManagementBean implements PriceManagement { 

    @PersistenceContext 
    private EntityManager em; 

    private List<PriceStep> priceSteps = Collections.synchronizedList(new ArrayList<PriceStep>()); 


    public PriceManagementBean(){ 


    } 


    @PostConstruct 
    public void init(){ 
     javax.persistence.Query query = em.createQuery("SELECT ps FROM PriceStep ps"); 
     List<PriceStep> res = query.getResultList(); 
      ..... 
     } 
} 
+0

См http://stackoverflow.com/questions/2399769/is-it-okay-to-pass-injected-entitymanagers -to-ejb-beans-helper-classes-and-use – mglauche

+0

Как и где добавляются PriceSteps в db? – Puce

+0

Ваш бит аннотируется как 'Stateful', так и' Singleton', что запрещено. Если ваш контейнер EJB не поддерживает EJB 3.1, возможно, компонент на самом деле является работоспособным, а PostConstruct работает с неопределенным контекстом транзакций, и ваш сервер приложений не поддерживает это? Какой сервер приложений вы используете? –

ответ

9

Кто-нибудь знает, почему он не работает в методе PostConstruct?

Причина 1 Вы не можете создать компонент, который в то же время @Stateful и @Singleton (ну вы не можете, но это будет иметь никакого смысла, так как Одиночки также Stateful), то есть одна из причин, у вас проблемы. Исключений нет, но там есть конфликт, вам нужно исправить это в первую очередь.

Только помните:

  • одноплодного боб боб, который mantains своего состояния. В приложении есть только один экземпляр Singleton, и он распространяется среди всех пользователей приложения. Кроме того, поскольку это общий (возможно, лучше сказать, параллельный) компонент, необходимо реализовать какой-то механизм блокировки, используя аннотацию @Lock.

  • Боба состояния - это фасоль, которая поддерживает каждое состояние после транзакции. При работе с
    Stateful бобами каждый пользователь получает копию компонента, который будет продолжаться до тех пор, пока сессии - продолжается или до тех пор, метод с аннотацией @Remove не называется

Причина 2 Даже если это работает, вы не сможете получить доступ к результатам, потому что вы храните их в объекте с именем res, доступном только из метода init(). Я полагаю, вы хотели бы присвоить это возвращаемое значение переменной priceSteps.

В любом случае, в вашем коде есть много чего не так, потому что вы не говорите все. Я не знаю, каковы ваши системные требования, но здесь я бы предложил вам простое решение, которое позволит вам получить доступ к базе данных:

Я полагаю, вы пытаетесь каким-то образом вернуть данные в жизненный цикл bean, потому что вы хотите избежать отправки запросов снова и снова, если bean is @Stateful. Дело в том, что вам не нужно это делать, вы все равно можете сделать свой bean @Stateless и избегать стресса вашей базы данных со многими запросами. Что вам нужно сделать, это создать @NamedQuery.

Так аннотировать объект PriceStep с @NamedQuery и там ввести строку запроса вы написали.В этой ссылке вы найдете информацию о том, как использовать @NamedQueries: http://docs.oracle.com/cd/B31017_01/web.1013/b28221/ent30qry001.htm

Следующая вещь, которую я хотел бы предложить вам, чтобы аннотировать ваш класс PriceManagementBean в * @Stateless *. Не беспокойтесь, если в каждом запросе создается новый entityManager, который вообще не затрагивает базу данных, поскольку он взаимодействует с моделью домена. Вам не нужен @PostConstruct, вы просто вызываете свой @NamedQuery всякий раз, когда вам это нужно, и все. Сервер приложений будет кэшировать его и возвращать каждому пользователю, который требует его, без взаимодействия с базой данных все время.

Здесь codesnipet:

@Entity 
@NamedQuery(
    name="allPriceSteps", 
    queryString="SELECT ps FROM PriceStep ps" 
) 
public class PriceStep implements Serializable { 
... 
} 

Теперь боба:

@Stateless 
public class PriceManagementBean implements PriceManagement { 

    @PersistenceContext 
    private EntityManager em; 

    public List<PriceStep> getAllPriceSteps() { 
     Query query = em.createNamedQuery("allPriceSteps"); 
     return query.getResultList(); 
    } 
} 

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

+0

Я испытываю ту же проблему, но ваш ответ не распространяется на мое дело. У нас есть кеш в виде компонента @ @ Singleton', который заполняется методом '@ PostConstruct'. Это сработало хорошо, но я начинаю испытывать проблемы во время перезаписи тестов. Я думаю, причина в том, что ранее мы запускали тесты с уже заполненной базой данных, но теперь мы пытаемся использовать HSQLDB в памяти. Поскольку тестовый запуск в транзакции, я подозреваю, что код в '@ PostConstruct' не является частью одной и той же транзакции, в результате чего появляется пустой список. Есть ли у вас какие-либо идеи по этому поводу? – Magnilex

+0

То же самое, и я не использую statefuls или что-то в этом роде. – momomo

-2

на основе ваших требований, пожалуйста, попробуйте следующее

  • Удалить @Stateful [НЕЛЬЗЯ использовать как в то время]

  • @Startup инициализирует одноплодный боб во время нанесения INIT [Пожалуйста, обратите внимание, что приложение не было полностью инициализировано]. Это может вызвать некоторую проблему при загрузке EntityManager, и я предполагаю, что мост EntityManager не был полностью инициализирован. Попробуйте вызвать инициализации после полного запуска приложения [т.е.] Удалить @Startup