2012-04-30 15 views
7

Po utworzeniu komponentu bean, chcę pobrać dane z bazy danych za pomocą EntityManager. W konstruktorze nie jest to możliwe, ponieważ EntityManager jest wstrzykiwany po wywołaniu konstruktora. Więc próbowałem to zrobić w metodzie z @PostConstruct. Zgodnie z API, po wykonaniu wszystkich iniekcji wywoływana jest metoda PostConstruct. Wykonanie zapytania działa, ale zawsze zwraca pustą listę. Jeśli używam tego samego zapytania w innej metodzie, zwraca poprawny wynik. Czy ktokolwiek wie, dlaczego nie działa w metodzie PostConstruct?EJB: Używanie EntityManager w metodzie 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

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

+0

W jaki sposób i gdzie są dodawane zapytania cenowe do bazy danych? – Puce

+0

Twoja fasola jest opisana zarówno jako "Stateful" i "Singleton", co nie jest dozwolone. Jeśli twój kontener EJB nie obsługuje EJB 3.1, być może komponent bean jest rzeczywiście stanowy, a PostConstruct działa z nieokreślonym kontekstem transakcji, a serwer aplikacji nie obsługuje go tak dobrze? Z jakiego serwera aplikacji korzystasz? –

Odpowiedz

9

Czy ktoś wie, dlaczego to nie działa w sposób PostConstruct?

Powód 1 Nie można utworzyć ziarna, które jest jednocześnie @Stateful i @Singleton (No można, ale to nie ma sensu, ponieważ Singletons są również Stateful), który jest jednym z powodów, masz kłopoty. Nie ma wyjątków, ale tam jest konflikt, musisz to najpierw naprawić.

Wystarczy pamiętać:

  • Singleton fasola szparagowa, że ​​jest mantains swój stan. W aplikacji jest tylko jedno wystąpienie Singleton i jest ono udostępniane wszystkim użytkownikom aplikacji. Ponieważ jest to wspólna (może lepiej powiedzieć współbieżna) komponent bean, istnieje potrzeba implementacji jakiegoś mechanizmu blokującego za pomocą adnotacji @Lock.

  • Stanowy fasolka to ziarno, które zachowuje każdy stan po transakcji. Podczas pracy z
    Stateful ziaren każdy użytkownik otrzymuje kopię fasoli, która będzie trwać tak długo, jak długo sesji - trwa, aż metody, z dopiskiem @Remove nazywa

Powód 2 nawet jeśli działa, nie będzie można uzyskać dostępu do wyników, ponieważ są przechowywane w obiekcie o nazwie res, który jest dostępny tylko z metody init(). Przypuszczam, że chcesz przypisać tę zwróconą wartość do zmiennej priceSteps.

W każdym razie jest wiele błędów w twoim kodzie, ponieważ nie mówisz wszystkiego. Nie wiem, jakie są twoje wymagania systemowe, ale tutaj dałbym ci proste rozwiązanie, które pozwoli ci uzyskać dostęp do bazy danych:

Przypuszczam, że próbujesz w jakiś sposób zwrócić dane w cyklu życia komponent bean, ponieważ chcesz uniknąć ponownego wysyłania zapytań, jeśli komponent bean jest @ Stanowia. Chodzi o to, że nie musisz tego robić, możesz nadal produkować swoją fasolę @Stateless i unikać obciążania bazy danych wieloma pytaniami. Co należy zrobić, to utworzyć numer @NamedQuery.

więc opisywać swój podmiot PriceStep z @NamedQuery i tam wpisać ciąg kwerendy napisałeś.W tym linkiem znajdziesz informacje na temat sposobu korzystania @NamedQueries: http://docs.oracle.com/cd/B31017_01/web.1013/b28221/ent30qry001.htm

Następną rzeczą, jaką proponujesz jest do opisywania klasa PriceManagementBean jak * @Stateless *. Nie martw się, jeśli w każdym żądaniu zostanie utworzony nowy podmiot zarządzający, który w ogóle nie obciąża bazy danych, ponieważ współdziała ona z modelem domeny. Nie potrzebujesz @PostConstruct, po prostu zadzwoń do @NamedQuery, kiedy tylko potrzebujesz i gotowe. Serwer aplikacji zapisze go w pamięci podręcznej i przekaże go każdemu użytkownikowi, który tego wymaga, bez interakcji z bazą danych.

Tutaj codesnipet:

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

Teraz fasoli:

@Stateless 
public class PriceManagementBean implements PriceManagement { 

    @PersistenceContext 
    private EntityManager em; 

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

Mam nadzieję, że jest to przydatne. Jeśli podasz więcej informacji na temat wymagań systemowych, możemy udzielić porady na temat najlepszej praktyki.

+0

Mam dokładnie ten sam problem, ale twoja odpowiedź nie obejmuje mojej sprawy. Mamy pamięć podręczną jako komponent '@ Singleton', który jest zapełniany metodą' @ PostConstruct'. To zadziałało dobrze, ale zaczynam doświadczać problemu podczas przepisywania testów. Myślę, że powodem jest to, że wcześniej przeprowadziliśmy testy przeciwko już zapełnionej bazie danych, ale teraz próbujemy użyć HSQLDB w pamięci. Od czasu uruchomienia testu w transakcji podejrzewam, że kod w '@ PostConstruct' nie jest częścią tej samej transakcji, co skutkuje pustą listą. Czy masz jakieś pomysły na ten temat? – Magnilex

+0

To samo tutaj, i nie używam stanów lub niczego w tym stylu. – momomo

-2

podstawie zapotrzebowania spróbuj wykonać następujące

  • Usuń @Stateful [NIE używać obu naraz]

  • @Startup będzie zainicjować singleton fasoli podczas aplikacji INIT [Proszę zwróć uwagę, że aplikacja NIE została w pełni zainicjalizowana]. Mogło to spowodować problem z ładowaniem EntityManager i założyć, że most EntityManager nie został całkowicie zainicjowany. Spróbuj zadzwonić init po całkowitym uruchomieniu aplikacji [czyli] Usuń @Startup

Powiązane problemy