EJB: использование EntityManager в методе PostConstruct
после построения компонента я хочу получить данные из базы данных, используя EntityManager. Это невозможно в конструкторе, потому что EntityManager вводится после вызова конструктора. Так что я пытался сделать это в метод с аннотацией @PostConstruct. Согласно API, методы PostConstruct вызываются после выполнения всех инъекций. Выполнение запроса работает, но он всегда возвращает пустой список. Если я использую тот же запрос в другом методе, он возвращает правильный результат. Кто-нибудь знает, почему он не работает в 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();
.....
}
}
2 ответов
кто-нибудь знает, почему он не работает в методе PostConstruct?
Причина 1 Вы не можете создать боб, который одновременно @Stateful и @Singleton (Ну, вы можете, но это не будет иметь смысла, так как синглтоны также являются Stateful), это одна из причин, по которой у вас возникли проблемы. Нет никаких исключений, но там есть конфликт, вам нужно сначала это исправить.
просто помню:
бин-это боб, который поддерживает его состояние. Существует только один экземпляр синглтона в приложении, и он совместно используется всеми пользователями приложения. Кроме того, поскольку это общий(возможно, лучше сказать параллельный) Боб, необходимо реализовать какой-то механизм блокировки с помощью аннотации @Lock.
боб с состоянием-это боб, который поддерживает каждое состояние после транзакции. При работе с
Stateful бобы каждый пользователь получает копию bean, которая будет длиться до тех пор, пока сеанс-длится или пока метод с аннотацией @Remove не будет вызван
Причина 2 Даже если он работает, вы не сможете получить доступ к результатам, потому что вы храните их в объекте под названием res, который доступен только изнутри метода init (). Полагаю, вы хотели бы присвоить это возвращаемое значение переменной priceSteps.
в любом случае в вашем коде есть много ошибок, потому что вы не говорите всего. Я не знаю, каковы ваши системные требования, но здесь я бы дал вам простое решение, которое позволит вам получить доступ к базе данных:
Я полагаю, вы пытаетесь каким-то образом вернуть данные в жизненном цикле bean, потому что вы хотите избежать отправки запросов снова и снова, если bean @Stateful. Дело в том, что вам не нужно этого делать, вы все еще можете сделать свой боб @ и не подчеркивайте свою базу данных многими запросами. Что вам нужно сделать, это создать @NamedQuery.
Итак, аннотируйте свою сущность PriceStep С @NamedQuery и введите строку запроса, которую вы написали. В этой ссылке вы найдете информацию о том, как использовать @NamedQueries: http://docs.oracle.com/cd/B31017_01/web.1013/b28221/ent30qry001.htm
следующее, что я предложил бы вам аннотировать свой класс PriceManagementBean as *@*. Не беспокойтесь, если в каждом запросе создается новый 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();
}
}
Я надеюсь, что это полезно. Если вы дадите больше информации о своих системных требованиях, мы можем дать вам совет по лучшей практике.
на основе вашего требования, пожалуйста, попробуйте следующее
Удалить @Stateful [нельзя использовать оба одновременно]
@Startup инициализирует одноэлементный компонент во время инициализации приложения [обратите внимание, что приложение не было полностью инициализировано]. Это может вызвать некоторые проблемы при загрузке EntityManager, и я предполагаю, что мост EntityManager не был полностью инициализирован. Попробуйте вызвать init после завершения запуска приложения [т. е.,] Удалить @Startup