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