2012-06-12 6 views
13

Używam EclipseLink 2.3.0. Mam metodę, która Wołam z testów jednostkowych (stąd na zewnątrz pojemnika, bez JTA), który wygląda tak:JPA/EclipseLink: Czy EntityManager.getTransaction() tworzy nową transakcję, czy zwraca aktywną?

EntityManager em = /* get an entity manager */; 
em.getTransaction().begin(); 
// make some changes 
em.getTransaction().commit(); 

Zmiany te nie są utrwalone w bazie danych, a wyglądało na to za od dłuższego czasu zorientował się, że EntityManager.getTransaction() faktycznie zwraca NOWY EntityTransaction, a nie ten sam w obu wywołaniach. Efekt jest taki, że pierwsze połączenie tworzy nową transakcję i rozpoczyna ją, a drugie połączenie tworzy INNĄ transakcję i zatwierdza ją. Ponieważ pierwsza transakcja nigdy nie została zatwierdzona, zmiany nie są zapisywane. Zweryfikowaliśmy to tak:

log.info(em.getTransaction().toString()); 
log.info(em.getTransaction().toString()); 

co spowodowało w tych komunikatów dziennika:

INFO: org.ecl[email protected]1e34f445 
INFO: org.ecl[email protected]706a4d1a 

Dwa sprawdzeniu, że istnieją dwa różne instancje innego obiektu identyfikatora. Zmiana kodu na:

EntityManager em = /* get an entity manager */; 
EntityTransaction tx = em.getTransaction(); 
tx.begin(); 
// make some changes 
tx.commit(); 

... naprawiono problem. Teraz po uruchomieniu kodu widzę instrukcje SQL wygenerowane w celu wykonania pracy z bazą danych i po przejrzeniu w bazie danych dane zostały zmienione.

Byłem nieco zaskoczony tym wynikiem, ponieważ widziałem wiele przykładów kodu online (ogólnie dla JPA i dla EclipseLink), które polecają kod używany do zarządzania transakcjami. Szukałem dużo informacji o tym, ale niczego nie znalazłem. Więc co się dzieje?

Sprawdziłem specyfikację JPA pod kątem czegoś, co dokładnie określa, co robi getTransaction() i nie było to konkretne, jeśli transakcja jest nowa lub taka sama. Czy istnieje ustawienie w persistence.xml, które kontroluje to? Czy zachowanie jest specyficzne dla każdej implementacji specyfikacji JPA?

Dziękuję bardzo za wszelkie informacje lub wskazówki.

Odpowiedz

1

Specyfikacja JPA (patrz punkt 7.5.4) zawiera wyraźne przykłady pokazujące użycie getTransaction() w celu rozpoczęcia i zatwierdzenia transakcji. Więc twój kod powinien być w porządku.

Twój test pokazuje, że masz dwa różne obiekty, ale to nie znaczy, że ta sama transakcja nie jest używana. Może zwracany obiekt jest po prostu jakimś proxy dla pojedynczego, prawdziwego obiektu transakcyjnego.

A może transakcja została zatwierdzona lub wycofana wewnątrz kodu ukrytego pod numerem // make some changes.

+1

Może powinienem być bardziej zrozumiały - kod, który napisałem, NIE działa. Wprowadziłem zmiany w tym pytaniu w celu wyjaśnienia. –

+0

Rozumiem to. Chodzi mi o to, że * powinien * działać, ponieważ specyfikacja JPA zawiera próbki kodu whet 'em.getTransaction()' jest używane do rozpoczynania i zatwierdzania transakcji. Musi to być błąd w EclipseLink, chyba że, jak już powiedziałem, kod pomiędzy początkiem i zatwierdzeniem już zatwierdza lub wycofuje transakcję. Moja odpowiedź nie jest rozwiązaniem twojego problemu, ale potwierdzeniem, że kod powinien zadziałać. Sugeruję zgłoszenie błędu do EclipseLink. –

5

Używanie getTransaction() działa w JPA i EclipseLink (tak działają nasze własne testy).

Zgaduję, że robisz coś bardzo dziwnego.

Czy używasz Springa lub innej warstwy? Do testu należy dołączyć cały kod i plik persistence.xml. Upewnij się, że nie korzystasz z JTA w pliku persistence.xml.

+0

getTransaction() powinien rzucić wyjątek IllegalStateException, jeśli zostanie wywołany w menedżerze encji JTA. –

+0

Bez sprężyny, bez JTA, jest wywoływana z testu JUnit poza kontenerem. Kod w "make some changes" to 4 linie, tworzenie nowego obiektu, ustawianie wartości całkowitej, scalanie i flush. Kiedy dostanę minutę, utworzę destylowany przykład. Być może jest to błąd EclipseLink. –

0

Czy próbowałeś użyć persist before commit:?

Employee employee = new Employee("Samuel", "Joseph", "Wurzelbacher"); 
    em.getTransaction().begin(); 
    em.persist(employee); 
    em.getTransaction().commit();