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
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 .
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 EntityManager
do 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ż
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:
- jeśli chcesz ściśle przestrzegać JSR-220, nigdy nie używaj EntityManager w singletonach do czasu zsynchronizowania dostępu do niego.
- 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ę.
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