Należy umieścić @Transactional
w DAO
klasach i / lub ich metod czy też lepiej opisywanie klas usług, które są wzywające użyciu obiektów DAO? Czy ma sens dodawanie adnotacji do obu „warstw”?
Należy umieścić @Transactional
w DAO
klasach i / lub ich metod czy też lepiej opisywanie klas usług, które są wzywające użyciu obiektów DAO? Czy ma sens dodawanie adnotacji do obu „warstw”?
Odpowiedzi:
Myślę, że transakcje należą do warstwy usług. To ten, który wie o jednostkach pracy i przypadkach użycia. To właściwa odpowiedź, jeśli masz kilka wstrzyknięć DAO do Usługi, które muszą współpracować w ramach jednej transakcji.
Zasadniczo zgadzam się z innymi, stwierdzając, że transakcje zwykle rozpoczynane są na poziomie usługi (w zależności od wymaganej szczegółowości).
Jednak w międzyczasie zacząłem również dodawać @Transactional(propagation = Propagation.MANDATORY)
do mojej warstwy DAO (i innych warstw, które nie mogą uruchamiać transakcji, ale wymagają już istniejących), ponieważ o wiele łatwiej jest wykryć błędy, w przypadku których zapomniałeś rozpocząć transakcję w abonencie wywołującym ( np. usługa). Jeśli Twoje DAO jest opatrzone adnotacją o obowiązkowej propagacji, otrzymasz wyjątek stwierdzający, że po wywołaniu metody nie ma żadnej aktywnej transakcji.
Mam również test integracji, w którym sprawdzam wszystkie ziarna (postprocesor bean) pod kątem tej adnotacji i nie udaje się, jeśli istnieje @Transactional
adnotacja z propagacją inną niż Obowiązkowa w fasoli, która nie należy do warstwy usług. W ten sposób upewniam się, że nie rozpoczynamy transakcji na niewłaściwej warstwie.
@Transactional
klasę implementacji usługi i powinienem wdrożyć implementację klasy @Transactional(propagation = MANDATORY)
DAO (repozytorium)?
Adnotacje transakcyjne należy umieszczać wokół wszystkich nierozdzielnych operacji.
Na przykład połączenie to „zmień hasło”. Składa się z dwóch operacji
Zatem w powyższym przypadku, jeśli audyt się nie powiedzie, to czy zmiana hasła również nie powiedzie się? Jeśli tak, to transakcja powinna wynosić około 1 i 2 (czyli w warstwie usługi). Jeśli wiadomość e-mail nie powiedzie się (prawdopodobnie powinna być w tym bezpieczna, aby nie zawiodła), to czy powinna wycofać hasło zmiany i audyt?
To są pytania, które musisz zadać, decydując, gdzie umieścić @Transactional
.
Prawidłową odpowiedzią dla tradycyjnych architektur Spring jest umieszczenie semantyki transakcyjnej w klasach usług z powodów, które inni już opisali.
Pojawiający się trend na wiosnę to projektowanie oparte na domenie (DDD). Spring Roo ładnie ilustruje ten trend. Chodzi o to, aby obiekt domeny POJO był znacznie bogatszy niż w typowych architekturach Spring (zwykle są one anemiczne ), a w szczególności, aby umieścić semantykę transakcji i trwałości na samych obiektach domeny. W przypadkach, gdy wszystko, czego potrzeba, to proste operacje CRUD, kontrolery sieciowe działają bezpośrednio na obiektach POJO obiektu domeny (w tym kontekście działają jako podmioty) i nie ma warstwy usług. W przypadkach, gdy potrzebna jest jakaś koordynacja między obiektami domeny, możesz obsłużyć komponent bean usługi za pomocą@Transaction
zgodnie z tradycją. Można ustawić propagację transakcji na obiektach domeny REQUIRED
tak, aby obiekty domeny korzystały z wszelkich istniejących transakcji, takich jak transakcje rozpoczęte w komponencie bean usługi.
Technicznie technika ta wykorzystuje AspectJ i <context:spring-configured />
. Roo używa definicji typu AspectJ w celu oddzielenia semantyki encji (transakcji i trwałości) od elementów obiektu domeny (zasadniczo pól i metod biznesowych).
Normalnym przypadkiem byłoby umieszczanie adnotacji na poziomie warstwy usługi, ale tak naprawdę zależy to od twoich wymagań.
Adnotacje w warstwie usług skutkują dłuższymi transakcjami niż adnotacje na poziomie DAO. W zależności od poziomu izolacji transakcji, który może powodować problemy, ponieważ transakcje współbieżne nie zobaczą nawzajem swoich zmian, np. POWTARZANE CZYTANIE.
Adnotacje na temat DAO sprawią, że transakcje będą jak najkrótsze, z tą wadą, że funkcjonalność, którą ujawnia twoja warstwa usług, nie będzie wykonywana w pojedynczej transakcji (możliwej do rozszerzenia).
Adnotacja na obu warstwach nie ma sensu, jeśli tryb propagacji jest ustawiony na domyślny.
Kładę @Transactional
na @Service
warstwie i ustawiam rollbackFor
dowolny wyjątek oraz w readOnly
celu dalszej optymalizacji transakcji.
Domyślnie @Transactional
będzie szukał tylko RuntimeException
(Niezaznaczone wyjątki), ustawiając wycofywanie na Exception.class
(Sprawdzone wyjątki), będzie przywracał dla każdego wyjątku.
@Transactional(readOnly = false, rollbackFor = Exception.class)
Zobacz Sprawdzone vs. Niezaznaczone wyjątki .
Czy ma sens dodawanie adnotacji do obu „warstw”? - czy nie ma sensu adnotować zarówno warstwy usługi, jak i warstwy dao - jeśli chce się upewnić, że metoda DAO jest zawsze wywoływana (propagowana) z warstwy usługi z propagacją „obowiązkową” w DAO? Zapewniłoby to pewne ograniczenie dla wywoływania metod DAO z warstwy interfejsu użytkownika (lub kontrolerów). Ponadto - szczególnie w przypadku testowania jednostkowego warstwy DAO - adnotacja DAO zapewni również przetestowanie jej pod kątem funkcjonalności transakcyjnej.
propagation=Propagation.REQUIRES_NEW
. W przeciwnym razie w większości przypadków, w tym propagacji = obowiązkowe, DAO po prostu weźmie udział w istniejącej transakcji rozpoczętej przez warstwę usługi.
Ponadto Spring zaleca stosowanie adnotacji tylko do konkretnych klas, a nie interfejsów.
http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
Do transakcji na poziomie bazy danych
głównie używałem @Transactional
w DAO tylko na poziomie metody, więc konfiguracja może być specyficzna dla metody / przy użyciu domyślnej (wymagane)
Metoda DAO, która pobiera dane (wybierz ..) - nie potrzebuje
@Transactional
tego, może prowadzić do narzutu z powodu przechwytywania transakcji / i proxy AOP, które również muszą zostać wykonane.
Otrzymają metody DAO, które wstawiają / aktualizują @Transactional
bardzo dobry blog o transakcjach
Na poziomie aplikacji -
używam transakcji dla logiki biznesowej Chciałbym mieć możliwość rolbacka w przypadku nieoczekiwanego błędu
@Transactional(rollbackFor={MyApplicationException.class})
public void myMethod(){
try {
//service logic here
} catch(Throwable e) {
log.error(e)
throw new MyApplicationException(..);
}
}
Transactional
naJava
Zwykle transakcję należy umieścić w warstwie usługi.
Ale, jak powiedziano wcześniej, atomowość operacji mówi nam, gdzie adnotacja jest konieczna. Tak więc, jeśli używasz frameworków takich jak Hibernacja, w których pojedyncza operacja „zapisz / aktualizuj / usuń / ... modyfikacja” na obiekcie może potencjalnie zmodyfikować kilka wierszy w kilku tabelach (z powodu kaskady przez wykres obiektów) oczywiście powinno być również zarządzanie transakcjami dla tej konkretnej metody DAO.
@Transactional
Adnotacje należy umieszczać wokół wszystkich nierozdzielnych operacji. Korzystanie z @Transactional
propagacji transakcji jest obsługiwane automatycznie. W takim przypadku, jeśli inna metoda zostanie wywołana przez bieżącą metodę, wówczas ta metoda będzie miała opcję dołączenia do bieżącej transakcji.
Weźmy więc przykład:
Mamy czyli 2 modelu Country
i City
. Mapowanie relacyjne Country
i City
model jest jak Country
można mieć wiele Miast, więc mapowanie jest jak,
@OneToMany(fetch = FetchType.LAZY, mappedBy="country")
private Set<City> cities;
Tutaj Kraj jest mapowany na wiele miast z ich pobieraniem Lazily
. Więc tutaj pojawia się rola, @Transactinal
kiedy odzyskujemy obiekt Country z bazy danych, wtedy otrzymamy wszystkie dane obiektu Country, ale nie otrzymamy zbioru miast, ponieważ pobieramy miasta LAZILY
.
//Without @Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//After getting Country Object connection between countryRepository and database is Closed
}
Kiedy chcemy uzyskać dostęp do Zestawu Miast z obiektu kraju, wówczas otrzymamy wartości zerowe w tym Zestawie, ponieważ obiekt Zestawu utworzony tylko w tym Zestawie nie jest inicjowany z danymi tam, aby uzyskać wartości Zestawu, którego używamy, @Transactional
tj.
//with @Transactional
@Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of @Transactinal
Object object = country.getCities().size();
}
Zasadniczo @Transactional
usługa może wykonywać wiele połączeń w jednej transakcji bez zamykania połączenia z punktem końcowym.
@Transactional
naprawdę jest
Lepiej mieć go w warstwie serwisowej! Wyjaśnia to jasno jeden z artykułów, z którymi się wczoraj spotkałem! Oto link , który możesz sprawdzić!
@Transactional
Należy stosować na warstwie usługowej, ponieważ zawiera logikę biznesową. Warstwa DAO zwykle ma tylko operacje CRUD bazy danych.
// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
}
Dokument wiosenny: https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html
Warstwa serwisowa jest najlepszym miejscem do dodawania @Transactional
adnotacji, ponieważ większość logiki biznesowej jest tutaj dostępna, zawiera zachowanie przypadków użycia na poziomie szczegółów.
Załóżmy, że dodajemy go do DAO, a z usługi nazywamy 2 klasy DAO, jedna nie powiodła się, a druga zakończyła się sukcesem, w tym przypadku, jeśli @Transactional
nie jest w służbie, jedna baza danych zatwierdzi, a druga przywróci.
Dlatego moim zaleceniem jest mądre stosowanie tej adnotacji i używanie jej tylko w warstwie serwisowej.
Przede wszystkim określmy, gdzie musimy użyć transakcji ?
Myślę, że poprawna odpowiedź brzmi - kiedy musimy upewnić się, że sekwencja akcji zostanie zakończona razem jako jedna operacja atomowa lub nie zostaną wprowadzone żadne zmiany, nawet jeśli jedna z akcji zakończy się niepowodzeniem.
Dobrze znaną praktyką jest wprowadzanie logiki biznesowej do usług. Metody serwisowe mogą więc zawierać różne działania, które muszą być wykonywane jako pojedyncza logiczna jednostka pracy. Jeśli tak, to taką metodę należy oznaczyć jako transakcyjną . Oczywiście nie każda metoda wymaga takich ograniczeń, więc nie musisz oznaczać całej usługi jako transakcyjnej .
Co więcej - nie zapomnij wziąć pod uwagę, że @Transactional może oczywiście obniżyć wydajność metody. Aby zobaczyć cały obraz, musisz znać poziomy izolacji transakcji. Wiedząc, że może to pomóc uniknąć korzystania z @Transactional tam, gdzie nie jest to konieczne.
Lepiej zachować @Transactional w oddzielnej środkowej warstwie między DAO a warstwą usług. Ponieważ wycofywanie jest bardzo ważne, możesz umieścić całą manipulację DB w środkowej warstwie i zapisać logikę biznesową w Warstwie usług. Środkowa warstwa będzie współdziałać z twoimi warstwami DAO.
Pomoże Ci to w wielu sytuacjach, takich jak ObjectOptimisticLockingFailureException - ten wyjątek występuje tylko po zakończeniu transakcji. Tak więc nie możesz złapać go w środkowej warstwie, ale możesz teraz złapać w warstwie usługi. Nie byłoby to możliwe, jeśli masz @Transactional w warstwie usługi. Chociaż możesz złapać kontroler, ale kontroler powinien być tak czysty, jak to możliwe.
Jeśli wysyłasz pocztę lub SMS-y w osobnym wątku po ukończeniu wszystkich opcji zapisywania, usuwania i aktualizacji, możesz to zrobić w usłudze po zakończeniu transakcji w warstwie środkowej. Ponownie, jeśli wspomnisz @Transactional w warstwie usług, poczta zostanie wysłana, nawet jeśli transakcja się nie powiedzie.
Posiadanie środkowej warstwy @Transaction pomoże uczynić kod lepszym i łatwiejszym w obsłudze. W przeciwnym razie, jeśli użyjesz w warstwie DAO, możesz nie być w stanie przywrócić wszystkich operacji. Jeśli używasz w warstwie usługi, w niektórych przypadkach może być konieczne użycie AOP (Programowanie zorientowane na aspekty).
Idealnie, warstwa usługowa (Manager) reprezentuje logikę biznesową i dlatego powinna być opatrzona adnotacjami z. @Transactional
Warstwa serwisowa może wywoływać różne DAO w celu wykonywania operacji DB. Załóżmy sytuacje, w których masz N operacji DAO w metodzie usługi. Jeśli Twoja pierwsza operacja DAO zakończy się niepowodzeniem, inne mogą być nadal przekazywane i skończysz niespójnym stanem DB. Adnotacja Warstwa usługi może uchronić Cię przed takimi sytuacjami.
Wolę używać @Transactional
w warstwie usług na poziomie metody.