Java CDI @PersistenceContext i thread safety

Czy EntityManager @ Inject [ed] jest następujący w klasach muliple threadsafe?

@PersistenceContext(unitName="blah")
private EntityManager em;

To pytanie ito wydaje się być specyficzne dla wiosny. Korzystam z usług Jave ee CDI

Author: Community, 2012-06-16

3 answers

Chociaż implementacje EntityManagernie są bezpieczne dla wątków, kontener Java EEwstrzykuje proxy, który deleguje wszystkie wywołania metod do transakcji związanej EntityManager. Dlatego każda transakcja działa z własną instancją EntityManager . Dotyczy to przynajmniej kontekstu trwałości o zasięgu transakcji (który jest domyślny).

Jeśli kontener wprowadzi nową instancję EntityManager w każdej fasoli, poniżej nie praca:

@Stateless
public class Repository1 {
   @EJB
   private Repository2 rep2;

   @PersistenceContext(unitName="blah", type = PersistenceContextType.TRANSACTION)
   private EntityManager em;

   @TransactionAttribute
   public void doSomething() {
      // Do something with em
      rep2.doSomethingAgainInTheSameTransaction();
   }
}

@Stateless
public class Repository2 {
   @PersistenceContext(unitName="blah", type = PersistenceContextType.TRANSACTION)
   private EntityManager em;

   @TransactionAttribute
   public void doSomethingAgainInTheSameTransaction() {
      // Do something with em
   }
}

doSomething- > doSomethingAgainInTheSameTransaction wywołanie odbywa się w jednej transakcji i dlatego beans musi współdzielić ten sam EntityManager . W rzeczywistości mają ten sam serwer proxy EntityManager, który deleguje wywołania do tego samego kontekstu trwałości.

Więc jesteś legalny używać EntityManager w singleton fasoli jak poniżej:

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class Repository {
   @PersistenceContext(unitName="blah", type = PersistenceContextType.TRANSACTION)
   private EntityManager em;
}

Innym dowodem jest to, że nie ma żadnej wzmianki o bezpieczeństwie wątku w EntityManager javadoc. Dlatego podczas pobytu w kontenerze Java EE nie powinieneś dbać o dostęp współbieżności do EntityManager .

 11
Author: polbotinka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-28 14:40:08

Ku mojemu wielkiemu zaskoczeniu (po latach używania jpa w wiosna) EntityManager nie jest bezpieczny dla wątku . Jest to zrozumiałe, jeśli pomyślimy o tym głębiej: EntityManager jest tylko opakowaniem wokół natywnej implementacji JPA, np. sesji w Hibernate, która z kolei jest opakowaniem wokół połączenia jdbc. To powiedziawszy EntityManager nie może być bezpieczny wątek, ponieważ reprezentuje jedno połączenie/transakcję z bazą danych.

Więc dlaczego to działa na wiosnę? Bo owija target EntityManager w proxy, w zasadzie używając ThreadLocal do utrzymywania lokalnego odniesienia dla każdego wątku. Jest to wymagane, ponieważ Aplikacje sprężynowe są zbudowane na singletonach, podczas gdy EJB używa puli obiektów.

I jak możesz sobie z tym poradzić w Twoim przypadku? Nie wiem cdi ale w EJB każda sesja bezstanowa i stanowa jest łączona, co oznacza, że tak naprawdę nie można wywołać metody tego samego EJB z wielu wątków w tym samym czasie. Tak więc EntityManager nigdy nie jest używany jednocześnie. To powiedziane, wstrzykiwanie EntityManager jest bezpieczne , przynajmniej do bezpaństwowych i stateful session beans.

Jednak wstrzykiwanie EntityManagerdo servletów i singletonów nie jest bezpieczne , ponieważ prawdopodobnie kilka wątków może uzyskać do nich dostęp w tym samym czasie, zakłócając to samo połączenie JDBC.

Zobacz też

 16
Author: Tomasz Nurkiewicz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-17 08:57:25

Czuję, że muszę się w to zagłębić, ponieważ moja pierwsza odpowiedź nie była do końca prawdziwa.

Odnoszę się do JSR-220 . W sekcji 5.2 uzyskanie Entitymanagera Znajdziesz:

Menedżer jednostek nie może być współdzielony między wieloma jednocześnie wykonywanie wątków. Zarządzanie podmiotem może być dostępne tylko w sposób jednowątkowy.

No to tyle. Możesz przestać tu czytać i nigdy nie używać EntityManager w singleton beans chyba że odpowiednio zsynchronizowane.

Ale wierzę, że jest zamieszanie w spec. Istnieją dwie różne implementacje EntityManager . Pierwszym z nich jest implementacja provider (mówiąc Hibernate), która nie jest zobowiązana do threadsafe.

Z drugiej strony istnieje implementacja kontenera EntityManager . Co również nie powinno być zgodne z powyższym. Ale implementacja containera działa jako proxy i deleguje wszystkie wywołania do rzeczywistego dostawcy EntityManager .

Tak dalej w spec w 5.9 Kontrakty Runtime pomiędzy kontenerem a Persistence Dostawca :

Do zarządzania kontekstem trwałości transakcji, jeśli nie ma jeszcze EntityManager skojarzonego z transakcją JTA: Kontener tworzy nowy menedżer encji, wywołując EntityManagerFactory.createEntityManager podczas pierwszego wywołania Kierownik Jednostki z uporem- ContextType.Transakcja następuje w zakresie metody biznesowej realizowanej w JTA transakcja.

Oznacza to z kolei, że dla każdej rozpoczętej transakcji będzie inna instancja EntityManager. Kod, który tworzy EntityManager {[4] } jest bezpieczny zgodnie z 5.3:

Metody interfejsu EntityManagerFactory to threadsafe.

Ale co jeśli istnieje EntityManager skojarzony z JTA transakcja? Kod, który wiąże EntityManager skojarzony z bieżącą transakcją JTA, może nie być zgodny ze specyfikacją threadsafe.

Ale nie mogę myśleć o implementacji serwera aplikacji, która działa poprawnie z EntityManager wstrzykiwany do bezstanowych fasoli, a nie poprawnie w singletonach.

Więc moje wnioski są następujące:

  1. jeśli chcesz ściśle przestrzegać JSR-220, nigdy nie używaj EntityManager w singletonach do czasu zsynchronizowania dostępu do niego.
  2. osobiście będę nadal używać EntityManager w singletonie, ponieważ moja implementacja serwera aplikacji działa z nim doskonale. Zanim to zrobisz, możesz sprawdzić swoją implementację.
 8
Author: polbotinka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-02 11:44:57